Skip to content
Accessibility

Screen Reader Testing

Test with VoiceOver, NVDA, and JAWS — learn what screen readers actually announce.

stellae.design

9 min read

Introduction

Screen readers are how blind and low-vision users experience the web. They read content aloud, announce UI structure, and provide keyboard shortcuts for navigation. Testing with screen readers is the only way to truly verify your accessibility — automated tools catch about 30% of issues.

The three major screen readers are VoiceOver (macOS/iOS, built-in), NVDA (Windows, free), and JAWS (Windows, commercial). Each interprets HTML and ARIA slightly differently, so testing with at least two is recommended.

This guide covers how to use each screen reader, what to listen for, and a testing checklist for common UI patterns.


Key Concepts

VoiceOver on macOS

bash
# Enable: Cmd + F5 (or System Settings → Accessibility → VoiceOver)
# Basic navigation:
# VO = Control + Option (the VoiceOver modifier)

VO + Right Arrow    # Move to next element
VO + Left Arrow     # Move to previous element
VO + Space          # Activate (click) current element
VO + U              # Open rotor (headings, links, landmarks)
VO + Shift + Down   # Enter a group/table
VO + Shift + Up     # Exit a group/table
Tab                 # Next focusable element
Shift + Tab         # Previous focusable element
VO + H              # Read current heading level

NVDA on Windows

bash
# Download from nvaccess.org (free)
# NVDA key = Insert (default) or Caps Lock

NVDA + Down Arrow   # Read from current position
Tab                 # Next focusable element
H                   # Next heading
D                   # Next landmark
K                   # Next link
F                   # Next form field
NVDA + F7           # Elements list (headings, links, landmarks)
NVDA + Space        # Toggle forms/browse mode

What to Listen For

  • Element role — 'button', 'link', 'heading level 2', 'navigation landmark'
  • Element name/label — 'Submit button', 'Search, edit text'
  • State — 'expanded', 'collapsed', 'checked', 'disabled', 'selected'
  • Context — 'list, 5 items', 'table, 3 columns, 10 rows'

Practical Examples

1. Testing a Navigation Menu

plain
// What VoiceOver should announce:
// "Navigation, main" (landmark)
// "Home, link" (first item)
// "Products, collapsed, popup button" (dropdown)
// After expanding: "Products, expanded, popup button"
// "Category A, link" (submenu item)

// Common issues:
// - Menu not announced as navigation landmark
// - Dropdown state (expanded/collapsed) not announced
// - Focus doesn't move into submenu on expand
// - No way to close menu with Escape key

2. Testing a Dialog/Modal

html
// Expected behavior:
// 1. Focus moves to dialog on open
// 2. Screen reader announces dialog title
// 3. Tab cycles within dialog (focus trap)
// 4. Escape closes dialog
// 5. Focus returns to trigger element

// Test:
<dialog aria-labelledby="dialog-title" aria-describedby="dialog-desc">
  <h2 id="dialog-title">Confirm Deletion</h2>
  <p id="dialog-desc">This action cannot be undone.</p>
  <button onClick={onCancel}>Cancel</button>
  <button onClick={onConfirm}>Delete</button>
</dialog>

3. Testing Checklist

markdown
## Screen Reader Testing Checklist

### Page Structure
- [ ] Page title is descriptive
- [ ] Headings form a logical hierarchy (h1 → h2 → h3)
- [ ] Landmarks are present (nav, main, footer)
- [ ] Skip link works and jumps to main content

### Interactive Elements
- [ ] All buttons have accessible names
- [ ] Links describe their destination (not "click here")
- [ ] Form fields have associated labels
- [ ] Error messages are announced
- [ ] Custom widgets announce role and state

### Dynamic Content
- [ ] Toast/notification is announced
- [ ] Loading states are communicated
- [ ] Content changes are announced via live regions
- [ ] Modal focus trapping works correctly

Best Practices

  • ✅ Test with at least two screen readers (VoiceOver + NVDA)
  • ✅ Navigate by headings to verify heading hierarchy
  • ✅ Test all interactive flows — forms, dialogs, dropdowns, tabs
  • ✅ Listen for element role, name, and state announcements
  • ✅ Test with screen reader in both browse mode and forms mode
  • ❌ Don't test only with automated tools — they miss interaction issues
  • ❌ Don't add aria-label to everything — too much labeling is noisy

Common Pitfalls

  • Testing only with VoiceOver — NVDA and JAWS behave differently with ARIA
  • Not testing dynamic content — SPAs frequently break screen reader announcements
  • Forgetting to test with different verbosity settings — users customize their experience
  • Using VoiceOver cursor instead of Tab — real users primarily use Tab for interactive elements

Accessibilityaccessibility

Was this article helpful?