Screen Reader Testing Basics
Get started with VoiceOver, NVDA, and TalkBack — what to listen for, a smoke-test script, and how SR testing pairs with the a11y tree.
- accessibility
- screen-reader
Automated tools don’t hear your UI. Screen reader (SR) testing is how you validate names, roles, states, live regions, and reading order. You don’t need to be a daily SR user to run a valuable smoke test on critical flows.
Docs: WebAIM NVDA, WebAIM VoiceOver, Accessibility tree.
Pick a stack
| OS | SR | Browser often used |
|---|---|---|
| macOS | VoiceOver | Safari (primary), Chrome |
| Windows | NVDA (free) | Firefox or Chrome |
| Android | TalkBack | Chrome |
| iOS | VoiceOver | Safari |
Test on one desktop SR thoroughly for engineering QA; expand before major releases.
VoiceOver quick start (macOS)
- Toggle: Cmd+F5
- VO keys: Control+Option (called VO)
- Next item: VO+Right
- Rotor: VO+U (headings, landmarks, links)
- Click/activate: VO+Space
NVDA quick start (Windows)
- Install from nvaccess.org
- Browse mode vs focus mode for forms
- Insert/NVDA key combinations for lists of headings/links
Smoke-test script (15 minutes)
- Load the page — hear page title?
- Landmarks: find
main,nav. - Headings list: outline make sense?
- Tab through primary actions — names clear?
- Complete the critical form — errors announced?
- Open modal — focus trapped; Escape works; restore?
- Dynamic toast — announced once?
Write bugs with: SR + browser + OS + steps + what was heard vs expected.
What “good” sounds like
- “Button, Submit” not “Button” empty
- “Checked, Remember me, checkbox”
- Dialog name read on open
- No endless “clickable” unlabeled divs
What to not over-index
Different SRs announce differently. Aim for correct roles/names/states in the accessibility tree rather than pixel-identical speech strings across all combos.
Pair with DevTools
Inspect Name / Role / Value in the Accessibility pane when speech is confusing. Fix the tree, retest SR.
Footguns
- Testing only with mouse + SR mouse tracking — use keyboard.
- Chrome-only VoiceOver on macOS for shipping Safari-critical apps.
- Fixing for one verbose SR setting and breaking others.
- No retest after “small” CSS changes that affect visibility to AT.
Interview out-loud answer
“I smoke-test critical journeys with VoiceOver or NVDA using keyboard, check landmarks/headings/names, and verify dialogs and live regions. I debug with the accessibility tree. Automation plus one SR pass catches different classes of bugs.”
Forms mode gotchas
NVDA and JAWS switch modes on form fields. If arrows stop working as you expect, you may be in focus mode. That’s expected for inputs — use Tab between fields. Document this for teammates new to SR testing so they don’t file false bugs.
Extra practice
Write a minimal demo in a scratch file or the playground: one happy path, one failure path, and one boundary input. If you cannot exhibit a bug that the pattern prevents, you do not own the concept yet — re-read the primary docs linked below and tighten the example until the failure is obvious.
Notes from real codebases
Teams that succeed here keep the rules mechanical: lint where possible, CI for the rest, and a short human checklist for what automation cannot see. Document exceptions with an owner name and a removal date so “temporary” escapes do not become permanent architecture.
Related on this site
- What is the accessibility tree
- Accessible names computation
- Automated axe testing limits
- Keyboard accessibility checklist
- aria-live regions
Further reading
Related guides
- Accessible Combobox PatternBuild or evaluate comboboxes with APG keyboard behavior, aria-expanded/activedescendant, and filterable listbox pairing.
- Accessible Forms ErrorsLabel inputs, associate errors with fields, announce failures, and avoid placeholder-only forms that break accessibility.
- Accessible Menus PatternAPG menu and menubar keyboard model — arrow navigation, escape to close, aria-expanded, and when a disclosure is enough.
- Accessible Modals PatternsModal dialogs that work: focus trap, Escape, return focus, aria-modal, and why native dialog or APG patterns beat div soup.
- Accessible Names ComputationHow browsers compute accessible names from content, labels, aria-label, and labelledby — and how that powers Testing Library queries.