Most developer accessibility knowledge stops at "add alt text to images" and "use semantic HTML." That is a start, but genuine accessibility is more nuanced and more interesting than that checklist suggests.
How Screen Readers Actually Navigate
Screen reader users do not experience a web page the way sighted users do. They navigate by headings, links, landmarks, and interactive elements — using keyboard shortcuts to jump between them.
This has immediate practical implications:
- Heading hierarchy matters. An
h3that is the first heading on a page because it "looks the right size" breaks navigation. Screen readers build a table of contents from headings. The hierarchy should make sense as a document outline. - Link text should be descriptive in isolation. "Click here" or "Read more" is meaningless when read out of the context of surrounding paragraph text. "Read our privacy policy" is navigable.
- Landmark regions help users skip large sections.
<nav>,<main>,<aside>,<footer>are not just semantic niceties — they create jump points that screen reader users depend on.
Keyboard Navigation Is Not Optional
Every interactive element in your application must be reachable and operable via keyboard. This matters for screen reader users, but also for power users, people with motor disabilities, and anyone who prefers keyboard navigation.
Test it yourself: disconnect your mouse and try to complete your application's main user flow using only Tab, Shift+Tab, Enter, Space, and Arrow keys. You will find problems immediately.
Common failures:
- Custom dropdown menus that only respond to click events
- Modal dialogs that do not trap focus (Tab key escapes the modal into background content)
- Click handlers on
<div>elements that are not reachable by keyboard
Focus Management in SPAs
Single-page applications have a specific accessibility challenge: when navigation happens client-side, the browser does not announce the new page to screen readers the way a full page load does.
When your route changes, move focus to a meaningful element — typically the main heading of the new page:
useEffect(() => {
const heading = document.querySelector('h1');
if (heading) {
heading.setAttribute('tabindex', '-1');
heading.focus();
}
}, [location.pathname]);Small change. Significant difference for users who rely on focus management to orient themselves after navigation.