// guide
Screen Reader Testing for Developers: Getting Started
Automated accessibility tools catch roughly 30% of issues. Screen reader testing catches the rest — problems with reading order, missing accessible names, incorrect ARIA roles, broken live regions, and focus management. You don't need to be an expert. Even basic testing finds critical bugs.
// 01 · why developers should test with screen readers
Why Developers Should Test with Screen Readers
Automated accessibility testing tools are valuable, but they can only catch approximately 30% of accessibility issues. They're good at flagging missing alt text, low color contrast, and missing form labels. But they can't tell you what a screen reader actually announces — or whether the experience makes sense to someone who can't see the screen.
Screen reader testing catches issues that automated tools miss entirely:
- Reading order — content read in an illogical sequence that doesn't match the visual layout
- Missing accessible names — interactive elements that announce as just "button" or "edit" with no purpose
- Incorrect ARIA roles — custom components that don't announce what they are
- Broken live regions — dynamic content updates that are never announced
- Focus management problems — focus getting lost after closing a modal, or not moving to newly loaded content
You don't need to be a screen reader power user. Even spending five minutes tabbing through your page with a screen reader running will surface issues you'd never catch any other way.
// 02 · which screen reader to use
Which Screen Reader to Use
There are four major screen readers, each tied to a specific platform. Here's what you need to know about each:
VoiceOver (macOS / iOS)
Built into every Mac and iPhone. Free, no installation needed — just turn it on. VoiceOver is a good starting point for developers on macOS. Use it with Safari, which is the best-supported browser for VoiceOver on Mac. Chrome and Firefox have inconsistent VoiceOver support.
NVDA (Windows)
Free and open source. NVDA holds roughly 30% market share among screen reader users. It's the best free option on Windows and is actively developed. Use it with Firefox or Chrome. Download from nvaccess.org.
JAWS (Windows)
The most established commercial screen reader, with roughly 50% market share among screen reader users. JAWS is a paid product, but it offers a 40-minute demo mode that restarts. Use it with Chrome or Edge. Available from Freedom Scientific.
TalkBack (Android)
Built into Android devices. Use TalkBack for mobile web testing on Android. It pairs with Chrome on Android.
// 03 · essential commands
Essential Commands
You don't need to memorize every command. These are the basics that cover most testing scenarios.
VoiceOver (macOS)
The VoiceOver modifier key (referred to as VO) is Ctrl+Option. All VoiceOver commands use this modifier.
| Key | Action |
|---|---|
| Cmd+F5 | Turn VoiceOver on or off |
| VO+Right Arrow | Move to next item |
| VO+Left Arrow | Move to previous item |
| VO+Space | Activate the current item |
| VO+U | Open the Rotor (navigation menu for headings, landmarks, links, and more) |
| VO+Cmd+H | Move to next heading |
| Use Rotor | Navigate by landmarks (select Landmarks in the Rotor with VO+U, then use arrow keys) |
NVDA (Windows)
The NVDA modifier key is Insert (or CapsLock if configured). NVDA uses two modes: Browse mode for reading content and Focus mode for interacting with form controls.
| Key | Action |
|---|---|
| Ctrl+Alt+N | Turn NVDA on |
| Down Arrow | Read next item (Browse mode) |
| Up Arrow | Read previous item (Browse mode) |
| Enter | Activate the current item |
| NVDA+F7 | Open Elements List (headings, links, landmarks, form fields) |
| H | Move to next heading (Browse mode) |
| D | Move to next landmark (Browse mode) |
JAWS (Windows)
The JAWS modifier key is Insert. Like NVDA, JAWS uses a virtual cursor for reading and a forms mode for interaction.
| Key | Action |
|---|---|
| Down Arrow | Read next item |
| Enter | Activate the current item |
| Insert+F6 | Open Headings List |
| H | Move to next heading |
| R | Move to next landmark |
// 04 · what to listen for
What to Listen For
When testing with a screen reader, focus on these key areas:
Accessible Names
Every interactive element should announce its purpose. A submit button should say "Submit, button" — not just "button." An email input should say "Email, edit text" — not just "edit." If a screen reader announces an element without a clear name, that element is missing an accessible name and needs a <label>, aria-label, or aria-labelledby attribute.
Role Announcements
Elements should announce what they are. Buttons should say "button." Links should say "link." Checkboxes should say "checkbox." Tabs should say "tab." If you've built a custom component that doesn't announce its role, you likely need to add the correct ARIA role or use the native HTML element instead.
State Changes
Dynamic states must update when they change. Expanded and collapsed sections, checked and unchecked checkboxes, selected tabs, and pressed toggle buttons should all announce their current state. If you toggle a Switch and the screen reader doesn't announce "on" or "off," or you expand an Accordion and it doesn't announce "expanded," the state is not being communicated.
Live Region Announcements
Toast notifications, form validation errors, and dynamic content updates should be announced without requiring focus to move. If you trigger a toast notification and the screen reader stays silent, the live region is missing or broken. These rely on role="status", role="alert", or aria-live attributes being present before the content updates.
Reading Order
Content should be read in a logical sequence that matches the visual layout. If the screen reader reads a sidebar before the main content, or reads a modal's background content instead of the modal itself, the DOM order or focus management needs to be fixed.
// 05 · a testing workflow
A Testing Workflow
Rather than testing randomly, follow a systematic approach that covers the most important areas:
- Open the page and listen to the page title — the screen reader should announce a descriptive page title. If it says "Untitled" or something generic, the
<title>element needs attention. - Navigate by landmarks — use the Rotor (VoiceOver), D key (NVDA), or R key (JAWS) to jump between landmarks. Are all major sections identified? You should hear navigation, main, and contentinfo (footer) at minimum.
- Navigate by headings — use VO+Cmd+H (VoiceOver) or H (NVDA/JAWS) to jump through headings. Is the heading hierarchy logical? Does it skip levels (h1 to h3 with no h2)?
- Tab through interactive elements — press Tab to move through all focusable elements. Does every button, link, and form control announce its name and role?
- Test specific components — open and close modals, switch between tabs, toggle switches, and use the combobox. Do they announce state changes? Can you operate them with the keyboard alone?
- Check dynamic content — trigger a toast notification, submit a form with errors. Are these updates announced without moving focus?
- Verify focus management — after closing a modal or dismissing a menu, does focus return to the element that triggered it? Or does it jump to the top of the page?
// 06 · common issues and fixes
Common Issues and Fixes
These are the most frequent problems developers discover during screen reader testing, along with how to fix them.
alt text to every meaningful image. For decorative images, use alt="" so the screen reader skips them entirely.
aria-label attribute (e.g., aria-label="Close", aria-label="Search") or use visually hidden text inside the button.
role="button" on an anchor tag that navigates to a new page, or a custom component with no role at all. Fix: use native HTML elements whenever possible (<button> for actions, <a> for navigation). Only add ARIA roles to custom-built components that have no native equivalent.
role="status" for polite announcements or role="alert" for urgent ones. The live region container must exist in the DOM before the content is injected into it.
element.focus()) but the screen reader doesn't announce it. This often happens when focusing a <div> or <section> that isn't natively focusable. Fix: add tabindex="-1" to the target element so it can receive programmatic focus, and make sure it has an accessible name (via a heading, aria-label, or aria-labelledby).
// 07 · next steps
Next Steps
Screen reader testing is the highest-value manual check you can run, but it's still one part of the picture. Pair it with the full Accessibility Testing Checklist to cover keyboard, visual, and cognitive checks in one structured pass, and lean on automated accessibility testing to catch the mechanical failures — missing labels, broken ARIA references, low contrast — before they reach a manual review.