Screen Reader Testing Guide: Testing with NVDA, VoiceOver, and JAWS
Screen reader testing is one of the most direct ways to verify that your application is accessible to blind and low-vision users. Unlike automated tools, screen reader testing reveals the actual user experience: what gets announced, in what order, and whether it makes sense.
This guide covers how to set up and use NVDA, VoiceOver, and JAWS, what to test in each user flow, and common failures you'll encounter.
Why Screen Reader Testing Cannot Be Automated
Automated tools check that ARIA attributes exist and have valid values. They cannot check:
- Whether announced text makes sense in context
- Whether reading order matches visual order
- Whether dynamic updates are announced at the right time
- Whether custom widgets behave as expected under different screen reader modes
- Browser/screen reader compatibility gaps (the same ARIA pattern may work in NVDA+Chrome but fail in JAWS+IE)
You need to use actual screen readers to find these issues.
Screen Reader + Browser Combinations to Test
Screen readers are tightly coupled to browsers. Different combinations produce different behavior. Test against the pairs your users actually use:
| Screen Reader | Best With | Platform | Cost |
|---|---|---|---|
| NVDA | Firefox or Chrome | Windows | Free |
| JAWS | Chrome or Edge | Windows | Paid ($90+/year) |
| VoiceOver | Safari | macOS | Built-in |
| VoiceOver | Safari | iOS | Built-in |
| TalkBack | Chrome | Android | Built-in |
| Narrator | Edge | Windows | Built-in |
Minimum viable test matrix for most web apps:
- NVDA + Firefox (Windows, largest user base, free)
- VoiceOver + Safari (macOS)
- VoiceOver + Safari (iOS — test on a real device if possible)
Setting Up NVDA
NVDA (NonVisual Desktop Access) is free, widely used, and the most practical screen reader for development testing on Windows.
Installation:
- Download from nvaccess.org
- Install (or run portable version)
- NVDA starts automatically and announces "NVDA started"
Key commands (Insert = NVDA modifier key):
| Action | Command |
|---|---|
| Start/stop speech | Insert + S |
| Read current line | Insert + Up |
| Read from cursor | Insert + Down (numpad) |
| Read window title | Insert + T |
| Read focus | Insert + Tab |
| Open NVDA menu | Insert + N |
| Toggle browse/focus mode | Insert + Space |
| Next heading | H |
| Next landmark | D |
| Next form control | F |
| Next link | K |
| List all headings | Insert + F7 (Elements List) |
Browse mode vs. Focus mode:
- Browse mode (default): Arrow keys navigate the page by character, word, or element. Screen reader intercepts keyboard input.
- Focus mode: Keystrokes pass through to the application. Automatically activates when you enter a form field or application region.
Understanding this distinction is critical for testing interactive components.
Setting Up VoiceOver (macOS)
VoiceOver is built into macOS. Enable it with Command + F5.
Key commands (VO = Control + Option):
| Action | Command |
|---|---|
| Start/stop VoiceOver | Command + F5 |
| Read next item | VO + Right |
| Read previous item | VO + Left |
| Interact with item | VO + Shift + Down |
| Stop interacting | VO + Shift + Up |
| Open rotor | VO + U |
| Next heading | VO + Command + H |
| Next landmark | VO + Command + L |
| Next form control | VO + Command + J |
| Read from beginning | VO + A |
The VoiceOver Rotor (VO + U) is essential for testing navigation. It shows lists of headings, links, form controls, tables, and landmarks. Verify your page structure makes sense in each list.
Setting Up VoiceOver (iOS)
Enable in Settings → Accessibility → VoiceOver.
Basic gestures:
- Swipe right: next item
- Swipe left: previous item
- Double tap: activate selected item
- Three-finger swipe up/down: scroll
- Two-finger scrub (Z gesture): go back
Test on a real device when possible — iOS screen reader behavior on Safari differs from the simulator.
What to Test in Each Flow
Page Load
- What is announced when the page loads?
- Is the page title meaningful? (NVDA reads it; VoiceOver announces it on focus)
- Does the skip navigation link work? (Tab to it, activate it, does focus move to main content?)
- Are there multiple
<h1>elements? Should there be only one?
Navigation
- Activate the screen reader, navigate to the top of the page
- Use the headings list (NVDA: Insert+F7, VoiceOver rotor) — does the outline make sense?
- Use the landmarks list — is there a
main,nav,footer? - Navigate with Tab key — are all interactive elements reachable?
- Navigate with H key (headings) — do headings describe their sections?
Forms
Forms are where the most accessibility failures concentrate.
- Tab to the first form field — is it announced with its label?
- Are required fields indicated to the screen reader? (not just visually)
- Submit with empty required fields — are error messages announced?
- Are error messages associated with their fields? (
aria-describedbyor proximity in DOM) - After successful submission — is success communicated?
Common form failures:
- Placeholder text used as label (disappears when typing, not announced consistently)
- Error message as sibling element not associated with the input
- Required indicator (*) not indicated in the accessible name
- Custom select/combobox that doesn't announce options
Modal Dialogs
- Open the modal — does focus move into it?
- Is the modal's role and name announced? (
role="dialog"+aria-labelledby) - Is focus trapped? (Tab should cycle within the modal only)
- Close the modal — does focus return to the trigger?
- Press Escape — does it close the modal?
Common modal failures:
- Focus doesn't move to modal on open
- Background content is still readable
- Focus doesn't return to trigger on close
Dynamic Content
Dynamic content (loading states, success messages, inline errors, live search results) must be announced.
- Trigger an async operation (search, form submit, data load)
- Wait for the result
- Is the result announced without requiring the user to navigate to it?
Use aria-live="polite" for non-urgent updates and aria-live="assertive" for errors.
<!-- Status region: receives injected text when content loads -->
<div
role="status"
aria-live="polite"
aria-atomic="true"
class="visually-hidden"
id="live-announcer">
</div>// After search results load
document.getElementById('live-announcer').textContent =
`${results.length} results found for "${query}"`;Images
- Navigate to images using the links/graphics list
- Are decorative images hidden? (
alt=""orrole="presentation") - Do informative images have meaningful alt text?
- Are complex images (charts, diagrams) described?
- Are images in links described by the alt text or surrounding context?
Testing alt text quality: Navigate to each image and read what's announced. Is it meaningful? "Graph" is not meaningful. "Bar chart showing 40% growth in Q3 2024" is.
Data Tables
- Navigate to the table
- Are column and row headers announced when moving between cells?
- For complex tables, are data cells associated with the right headers?
- If the table has a caption, is it announced?
Custom Widgets
Custom widgets (date pickers, carousels, autocomplete, tabs) require specific ARIA patterns. Test each one against the ARIA Authoring Practices Guide keyboard patterns.
For a tab panel:
- Navigate to the tab list
- Is the role announced ("tab", "tab list")?
- Use arrow keys to move between tabs — does active tab update?
- Is the selected state announced?
- Press Enter/Space to activate — does the panel content update?
Creating a Screen Reader Testing Checklist
Before each release, run through this checklist for new or changed features:
## Screen Reader Pre-release Checklist
### Setup
- [ ] NVDA + Firefox (Windows)
- [ ] VoiceOver + Safari (macOS)
### For each new/changed page:
- [ ] Page title is meaningful and unique
- [ ] Heading hierarchy makes sense as outline
- [ ] Skip link present and functional
- [ ] All landmarks present (main, nav, footer)
- [ ] All interactive elements reachable by Tab
- [ ] All form fields have labels
- [ ] Error messages associated with fields
- [ ] Modal focus behavior correct
- [ ] Dynamic updates announced
- [ ] Images have meaningful alt text or are hiddenCommon Screen Reader Testing Pitfalls
Using the screen reader wrong: If you're new to screen readers, spend 20 minutes learning basic navigation before testing. Testing without knowing the tool leads to false passes and false failures.
Testing only Chrome: Chrome has the best DevTools accessibility support but NVDA + Firefox and JAWS + Edge may behave differently.
Rushing through: Screen reader testing is slow. Budget 30–60 minutes per significant user flow.
Not testing with speech on: Some developers test with speech muted and rely on the caption. Turn the speech on — the timing, phrasing, and interruptions matter.