Screen Readers: Testing and Support Guide
Screen readers convert digital text into synthesized speech or braille — and testing with them is the only way to know if your website truly works for blind and low-vision users.
What You’ll Learn
By the end of this tutorial, you’ll understand the popular screen readers (NVDA, JAWS, VoiceOver, TalkBack, Orca), how to set up a testing workflow, write semantic HTML that screen readers understand, create effective alt text, use ARIA announcements correctly, and identify common screen reader failures.
Why Screen Reader Testing Matters
Screen readers are the primary tool for over 285 million blind and low-vision people worldwide. But automated accessibility tools catch only about 30% of screen reader issues. The only way to know if your site works is to test with an actual screen reader. At DodaTech, Doda Browser includes a “Screen Reader Preview” mode in DevTools that approximates how content is exposed to assistive technologies.
Screen Readers Learning Path
flowchart LR
A[Accessibility Overview] --> B[WCAG Compliance]
B --> C[ARIA Basics]
C --> D[Keyboard Navigation]
D --> E[Screen Readers]
E --> F[Accessible Forms]
E --> G[Accessible Images]
E:::current
classDef current fill:#f90,color:#fff,stroke:#333,stroke-width:2px
Popular Screen Readers
NVDA (NonVisual Desktop Access) — Windows, Free
NVDA is the most popular free screen reader. It’s open-source and used by millions worldwide. Installation takes 5 minutes, and it works with all major browsers (Chrome, Firefox, Edge).
Key shortcuts:
NVDA+Q— Exit NVDANVDA+Space— Browse mode / Focus mode toggleH— Navigate by headingK— Navigate by linkD— Navigate by landmarkTab— Navigate by focusable elementInsert+DownArrow— Say allNVDA+T— Read title
JAWS (Job Access With Speech) — Windows, Paid ($1,000+)
JAWS is the most widely used commercial screen reader, especially in government and enterprise settings. It has a steep learning curve but powerful features.
Key shortcuts:
Insert+Q— Exit JAWSInsert+F6— List of headingsInsert+F7— List of linksF6— Navigate by landmarksCtrl+Insert+Enter— Force virtual cursor on a control
VoiceOver — macOS/iOS, Free (built-in)
VoiceOver is built into every Mac, iPhone, and iPad. It’s the standard screen reader for Apple platforms.
Key shortcuts (macOS):
Cmd+F5— Toggle VoiceOverCtrl+Option+Right/Left— Navigate by itemCtrl+Option+U— Open Rotor (headings, links, landmarks)Ctrl+Option+Space— Activate itemCtrl+Option+Shift+DownArrow— Enter a container
Key shortcuts (iOS):
- Triple-click Side/Top button — Toggle VoiceOver
- Single-finger swipe right/left — Next/previous item
- Single-finger double-tap — Activate
- Two-finger swipe up — Read all from top
- Rotor (two-finger twist) — Navigate by heading, link, etc.
TalkBack — Android, Free (built-in)
TalkBack is Android’s built-in screen reader, following similar gestures to VoiceOver.
Key shortcuts:
- Volume up+down for 3 seconds — Toggle TalkBack
- Single-finger swipe right/left — Next/previous
- Single-finger double-tap — Activate
- Two-finger swipe up — Read from top
Orca — Linux, Free
Orca is the screen reader for Linux desktops (GNOME). It supports Firefox and LibreOffice.
Screen Reader Testing Workflow
Step 1: Install and Learn Basics
Choose one primary screen reader for your testing. For most developers, NVDA (free, widely used) is the best starting point.
Step 2: Disable Your Monitor
This sounds extreme, but it’s the best way to understand the screen reader experience. Close your eyes or turn off the monitor and try to complete tasks.
Step 3: Create a Testing Checklist
## Screen Reader Testing Checklist
### Navigation
- [ ] Can I find the main heading (H1)?
- [ ] Can I navigate by headings (H1-H6)?
- [ ] Can I find landmarks (nav, main, footer)?
- [ ] Can I access the skip link?
- [ ] Can I navigate by links?
### Forms
- [ ] Are all form fields announced with labels?
- [ ] Are required fields announced?
- [ ] Are error messages announced?
- [ ] Can I submit the form successfully?
- [ ] Is success confirmed after submission?
### Dynamic Content
- [ ] Are new content changes announced?
- [ ] Are modal dialogs announced when they open?
- [ ] Is focus moved into modals?
- [ ] Are status messages announced (loading, saving, errors)?
### Images
- [ ] Do all informative images have alt text?
- [ ] Are decorative images ignored (alt="")?
- [ ] Are complex images explained?Step 4: Common Test Flows
Test these key user flows with every feature:
- Find information — Navigate to a product description using only headings and links
- Complete a purchase — Fill a form, select options, submit, confirm
- Search — Find and use the search feature, navigate results
- Account management — Log in, update settings, log out
Semantic HTML for Screen Readers
Screen readers rely heavily on semantic HTML to convey meaning. Here’s how different elements are announced:
<!-- Headings — users navigate by heading level -->
<h1>Page Title</h1> → "Page Title, heading level 1"
<h2>Section</h2> → "Section, heading level 2"
<h3>Subsection</h3> → "Subsection, heading level 3"
<!-- Lists — announced with item count -->
<ul>
<li>Item 1</li> → "List, 3 items"
<li>Item 2</li> → "Item 1"
<li>Item 3</li> → "Item 2"
</ul> → "Item 3, out of list"
<!-- Links — focusable, announced as link -->
<a href="/page">Read more</a> → "Read more, link"
<!-- Buttons — announced as button -->
<button>Submit</button> → "Submit, button"
<!-- Landmarks — navigable via Rotor/D key -->
<nav>...</nav> → "Navigation landmark"
<main>...</main> → "Main landmark"
<footer>...</footer> → "Content info landmark"
<!-- Tables — announced with row/column info -->
<table>
<caption>Monthly Sales</caption>
<tr>
<th>Month</th>
<th>Amount</th>
</tr>
<tr>
<td>January</td>
<td>$5,000</td>
</tr>
</table>
→ "Table with 2 columns and 3 rows, Monthly Sales"
→ "Month column header, Amount column header"
→ "Row 2: January, $5,000"Alt Text Best Practices
Alt text is the single most impactful accessibility improvement you can make:
<!-- Informative image — describe the content and function -->
<img src="chart-q2.png"
alt="Bar chart showing Q2 2026 revenue: April $120K, May $145K, June $160K">
<!-- Functional image (link/button) — describe the action -->
<a href="/download">
<img src="download-icon.svg" alt="Download report PDF">
</a>
<!-- Decorative image — hide from screen readers -->
<img src="decorative-border.svg" alt="" role="presentation">
<!-- Complex image — link to detailed description -->
<figure>
<img src="organizational-chart.png"
alt="Organizational chart. Full description follows."
longdesc="#org-chart-desc">
<figcaption id="org-chart-desc">
<h3>Organizational Structure</h3>
<p>CEO: Jane Smith. Reports to CEO: CTO (John Doe),
CFO (Sarah Lee), COO (Mike Brown)...</p>
</figcaption>
</figure>Alt text rules to remember:
- Be concise but descriptive — usually 5-15 words
- Include key data from charts and graphs
- Don’t start with “Image of” or “Picture of” — screen readers announce “image” automatically
- End with a period so screen readers pause
ARIA Announcements
Using aria-live for Dynamic Updates
<!-- Shopping cart count — announces when items change -->
<div aria-live="polite" aria-atomic="true" id="cart-status">
Cart: 3 items ($45.00)
</div>
<script>
function addToCart(item) {
// ... update cart logic ...
document.getElementById('cart-status').textContent =
`Cart: ${cart.count} items ($${cart.total.toFixed(2)})`;
}
</script>
<!-- Status messages for form submission -->
<div role="status" id="form-status" aria-live="polite">
<!-- Empty by default, populated on form submit -->
</div>
<!-- Critical errors — interrupts immediately -->
<div role="alert" id="error-message">
Connection lost. Autosaving...
</div>When NOT to Use ARIA for Announcements
<!-- ❌ Bad — screen reader already announces this -->
<button onclick="submit()" aria-live="polite">Submit</button>
<!-- ❌ Bad — aria-live on a hidden element does nothing -->
<div hidden aria-live="polite">You have a new message</div>
<!-- ✅ Good — announce changes that aren't naturally announced -->
<div aria-live="polite" id="auto-save-status">
Draft saved at 10:45 AM
</div>Screen Reader Shortcuts Reference
Here’s a quick reference table for the most common screen reader commands:
| Action | NVDA (Windows) | VoiceOver (Mac) | JAWS (Windows) |
|---|---|---|---|
| Read next item | DownArrow | Ctrl+Option+Right | DownArrow |
| Read previous item | UpArrow | Ctrl+Option+Left | UpArrow |
| Activate item | Enter | Ctrl+Option+Space | Enter |
| Navigate headings | H | Ctrl+Option+Cmd+H | H |
| Navigate links | K | Ctrl+Option+Cmd+L | K |
| Navigate landmarks | D | Rotor → Landmarks | ; |
| Navigate form fields | F | Rotor → Form Controls | F |
| Read page title | NVDA+T | Ctrl+Option+T | Insert+T |
| Read from here | NVDA+DownArrow | Ctrl+Option+A | Insert+DownArrow |
| List all links | NVDA+F7 | Rotor → Links | Insert+F7 |
| Toggle focus mode | NVDA+Space | — | Enter (in forms) |
Testing with Real Users
While developer testing is essential, nothing replaces testing with actual screen reader users. Consider:
- Remote usability testing — Services like Fable or UserTesting connect you with disabled users
- Internal accessibility champions — Recruit and compensate disabled employees for testing
- Open feedback channels — Provide an accessibility feedback form on your site
<!-- Accessibility feedback link -->
<footer>
<p>
Having trouble using this site?
<a href="/accessibility-feedback">
Let us know how we can improve
</a>
</p>
</footer>Common Screen Reader Failures
1. Missing or Bad Alt Text
Images without alt text read the file name: “chart-q2-2026-dot-png”. Decorative images without alt="" are announced as “graphic”.
2. Unlabeled Form Fields
An <input> without a <label> or aria-label is announced as “edit, blank” — users have no idea what to type.
3. No Heading Structure
Pages without proper heading hierarchy force users to listen to every word to find what they need. Users can’t skip to sections.
4. Dynamic Content Not Announced
Content loaded via AJAX without aria-live is invisible to screen readers. Users don’t know new content appeared.
5. Unexpected Focus Changes
When a modal opens, a page section updates, or content rearranges without moving focus, screen reader users are lost.
6. Custom Widgets Without ARIA
A <div> styled to look like a tab switch but without role="tab", aria-selected, or aria-controls is just “clickable div” to a screen reader.
7. Auto-Updating Content
Countdown timers, stock tickers, or live feeds that update without aria-live="polite" and aria-atomic either aren’t announced or spew constant noise.
Practice Questions
1. What’s the difference between browse mode and focus mode in NVDA?
Browse mode (default) allows navigation via arrow keys and quick keys (H, K, D). Focus mode passes keystrokes through to the application (needed for forms, custom widgets). NVDA+Space toggles between them.
2. Why is heading structure important for screen reader users?
Screen reader users can navigate by heading level (H key, Rotor). A good heading structure lets them quickly find and jump to sections without listening to all content.
3. What’s the VoiceOver Rotor and how do you access it?
The Rotor (Ctrl+Option+U on Mac) is a menu that lists all headings, links, landmarks, form controls, and other elements on the page, allowing quick navigation.
4. Why should you test with the monitor off?
It forces you to experience the page as a blind user would. If you can complete all tasks without seeing the screen, your site is likely accessible.
5. Challenge: Install NVDA (free on Windows) or use VoiceOver (built into Mac). Navigate a website you built without looking at the screen. Complete three tasks: find the page title, navigate to a specific section, and submit a form. Document every issue you encounter.
Real-World Task
Create a screen reader testing protocol for your team. Include a standard testing checklist (based on the one in this tutorial), instructions for installing NVDA/VoiceOver, and a defect reporting template that includes the exact screen reader output received vs expected.
FAQ
Try It Yourself
Let’s create a screen reader testing helper that logs the accessibility tree:
// accessibility-tree-logger.js
// Paste in DevTools console to see the accessibility tree for the focused element
function logAccessibilityTree(element) {
if (!element) element = document.activeElement;
if (!element) element = document.body;
const log = [];
function getAccessibleNode(el) {
const tag = el.tagName.toLowerCase();
const role = el.getAttribute('role') || el.getAttribute('aria-role') || 'implicit';
const name = el.getAttribute('aria-label') ||
el.getAttribute('aria-labelledby')?.split(' ').map(id =>
document.getElementById(id)?.textContent
).filter(Boolean).join(' ') ||
el.textContent?.trim()?.substring(0, 50);
const description = el.getAttribute('aria-describedby')?.split(' ').map(id =>
document.getElementById(id)?.textContent
).filter(Boolean).join(' ') || null;
return {
element: `<${tag}>`,
role,
accessibleName: name || '(none)',
accessibleDescription: description,
state: {
hidden: el.hasAttribute('aria-hidden'),
disabled: el.disabled || el.getAttribute('aria-disabled') === 'true',
expanded: el.getAttribute('aria-expanded'),
checked: el.getAttribute('aria-checked'),
selected: el.getAttribute('aria-selected'),
},
tabIndex: el.tabIndex,
};
}
// Walk the element and its children
function walk(el) {
log.push(getAccessibleNode(el));
el.children && [...el.children].forEach(child => {
if (child.nodeType === 1) walk(child);
});
}
walk(element);
console.table(log);
}
// Usage: logAccessibilityTree(document.querySelector('nav'))
Expected behavior: The console shows a table with each element’s tag, role, accessible name, description, and states — exactly what screen readers “see.”
What’s Next
Congratulations on completing this Screen Readers tutorial! Here’s where to go from here:
- Practice daily — Navigate one page per day with NVDA or VoiceOver
- Build a project — Create a screen reader testing harness
- Explore related topics — Learn color contrast next
- Join the community — Discuss with other learners and share your progress
Remember: every expert was once a beginner. Keep coding!
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro