Accessibility in a routed application
Accessibility is part of navigation, loading, forms, and error recovery. It works best when it is built into the component contract instead of checked at the end.
Use the element that already has the behaviour
A button activates an action. A link moves to a location. A heading describes the structure beneath it. Choosing the correct element gives keyboard and assistive-technology behaviour without rebuilding it from div elements and event handlers.
Use ARIA to add missing context, not to disguise the wrong element. A div with role button still needs keyboard activation, focus styling, disabled behaviour, and every other detail a real button already provides.
Client navigation still needs a clear new-page experience
App Router navigation can replace content without a full browser load. Check where focus lands and whether the new page has a useful heading. A sighted user notices the content change immediately; a screen-reader user may need an announcement or a predictable focus target.
Keep a skip link near the beginning of the document and give the main region a stable id. This is especially valuable when a persistent header and documentation sidebar appear on every route.
<a className="skip-link" href="#main-content">
Skip to main content
</a>
<main id="main-content" tabIndex={-1}>
{children}
</main>Loading states should be calm and informative
Skeletons should preserve layout rather than flash dramatically. Avoid announcing every small streamed region as busy because a page with several Suspense boundaries can become noisy.
For an important action, expose a short status message and connect it to the relevant control. Respect reduced-motion preferences for orbital, parallax, and 3D effects. The experience should still make sense when animation is removed.
Drawers and dialogs must manage focus
When a mobile documentation drawer opens, focus should move into it. While it is open, keyboard focus should not disappear behind the overlay. Closing it should return focus to the button that opened it.
Escape should close a temporary overlay. Give the control an accessible name and expose its expanded state with aria-expanded. These details are small, but they decide whether the navigation can be used without a pointer.
Automated checks find only part of the problem
Lint rules and browser audits catch missing labels, invalid roles, and some contrast problems. They cannot tell whether the tab order is sensible or whether an error message is understandable.
Use the whole site with a keyboard. Zoom to 200 percent. Try a narrow viewport. Turn on reduced motion. Run at least one screen reader through the main journey. Fixing these problems usually improves the interface for everybody.
Can you explain “Accessibility in a routed application” without reaching for the API reference?
Describe the main trade-off, one failure mode, and the decision you would make in a real project.