Screen Reader Testing
Seth HobsonCommunityCreated by Seth Hobson
- Skill
- Guidelines
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a structured approach to validating web accessibility by testing directly with assistive technology. It covers the essential screen readers used by the majority of users, outlines testing priorities, and provides practical patterns for common UI components like modals, live regions, and tab interfaces. The guide emphasizes the importance of testing with real hardware and software rather than relying solely on simulators or automated tools, ensuring that dynamic content, focus management, and semantic structures are accessible to all users.
What it does
- Defines a testing hierarchy for major screen readers including NVDA, JAWS, and VoiceOver.
- Provides keyboard command references for navigating content, forms, and landmarks.
- Offers code patterns for accessible modals, live regions, and tab interfaces.
- Includes a debugging utility to log the accessible name, role, and state of DOM elements.
- Explains the distinction between browse and focus modes in screen reader software.
- Supplies a structured test script for systematic accessibility verification.
When to use it
- When validating the accessibility of a new web feature or component.
- When debugging issues where assistive technology fails to announce content correctly.
- When ensuring that dynamic updates in a single-page application are properly communicated.
- When performing a comprehensive accessibility audit of a web application.
- When verifying that keyboard navigation and focus management are implemented correctly.
Advantages
- Promotes testing with actual screen readers for authentic user experience validation.
- Reduces accessibility bugs by providing clear implementation patterns for common UI elements.
- Standardizes the testing process across different platforms and browsers.
- Helps developers understand how screen readers interpret semantic HTML and ARIA attributes.
- Provides actionable debugging techniques to inspect the accessibility tree.
Usage examples
- “How do I test if my modal dialog is accessible to screen reader users?”
- The skill provides a specific modal structure using role='dialog' and aria-modal='true', along with JavaScript examples for trapping focus and managing focus return, which you can use to verify your implementation.
- “What are the essential NVDA commands for navigating a web page?”
- The skill lists key NVDA commands including 'H' for headings, 'F' for form fields, 'K' for links, and 'Insert + Down' to read all content, along with instructions for switching between browse and focus modes.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/wshobson/screen-reader-testing/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip screen-reader-testing.zip -d .agents/skills
Documentation by Seth Hobson
Screen Reader Testing
Practical guide to testing web applications with screen readers for comprehensive accessibility validation.
When to Use This Skill
Validating screen reader compatibility
Testing ARIA implementations
Debugging assistive technology issues
Verifying form accessibility
Testing dynamic content announcements
Ensuring navigation accessibility
Core Concepts
1. Major Screen Readers
| Screen Reader | Platform | Browser | Usage |
|---|---|---|---|
| VoiceOver | macOS/iOS | Safari | ~15% |
| NVDA | Windows | Firefox/Chrome | ~31% |
| JAWS | Windows | Chrome/IE | ~40% |
| TalkBack | Android | Chrome | ~10% |
| Narrator | Windows | Edge | ~4% |
2. Testing Priority
Minimum Coverage:
1. NVDA + Firefox (Windows)
2. VoiceOver + Safari (macOS)
3. VoiceOver + Safari (iOS)
Comprehensive Coverage:
+ JAWS + Chrome (Windows)
+ TalkBack + Chrome (Android)
+ Narrator + Edge (Windows)3. Screen Reader Modes
| Mode | Purpose | When Used |
|---|---|---|
| Browse/Virtual | Read content | Default reading |
| Focus/Forms | Interact with controls | Filling forms |
| Application | Custom widgets | ARIA applications |
Before testing on macOS, read VoiceOver setup, commands, and checklists.
For the required iOS Safari coverage, read VoiceOver touch setup and gestures.
Before testing with NVDA, read NVDA setup, modes, commands, and test scripts.
Before testing with JAWS or TalkBack, read platform setup and commands.
Common Test Scenarios
1. Modal Dialog
<!-- Accessible modal structure -->
<div
role="dialog"
aria-modal="true"
aria-labelledby="dialog-title"
aria-describedby="dialog-desc"
>
<h2 id="dialog-title">Confirm Delete</h2>
<p id="dialog-desc">This action cannot be undone.</p>
<button>Cancel</button>
<button>Delete</button>
</div>// Focus management
function openModal(modal) {
// Store last focused element
lastFocus = document.activeElement;
// Move focus to modal
modal.querySelector("h2").focus();
// Trap focus
modal.addEventListener("keydown", trapFocus);
}
function closeModal(modal) {
// Return focus
lastFocus.focus();
}
function trapFocus(e) {
if (e.key === "Tab") {
const focusable = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
);
const first = focusable[0];
const last = focusable[focusable.length - 1];
if (e.shiftKey && document.activeElement === first) {
last.focus();
e.preventDefault();
} else if (!e.shiftKey && document.activeElement === last) {
first.focus();
e.preventDefault();
}
}
if (e.key === "Escape") {
closeModal(modal);
}
}2. Live Regions
<!-- Status messages (polite) -->
<div role="status" aria-live="polite" aria-atomic="true">
<!-- Content updates will be announced after current speech -->
</div>
<!-- Alerts (assertive) -->
<div role="alert" aria-live="assertive">
<!-- Content updates interrupt current speech -->
</div>
<!-- Progress updates -->
<div
role="progressbar"
aria-valuenow="75"
aria-valuemin="0"
aria-valuemax="100"
aria-label="Upload progress"
></div>
<!-- Log (additions only) -->
<div role="log" aria-live="polite" aria-relevant="additions">
<!-- New messages announced, removals not -->
</div>3. Tab Interface
<div role="tablist" aria-label="Product information">
<button role="tab" id="tab-1" aria-selected="true" aria-controls="panel-1">
Description
</button>
<button
role="tab"
id="tab-2"
aria-selected="false"
aria-controls="panel-2"
tabindex="-1"
>
Reviews
</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
Product description content...
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
Reviews content...
</div>// Tab keyboard navigation
tablist.addEventListener("keydown", (e) => {
const tabs = [...tablist.querySelectorAll('[role="tab"]')];
const index = tabs.indexOf(document.activeElement);
let newIndex;
switch (e.key) {
case "ArrowRight":
newIndex = (index + 1) % tabs.length;
break;
case "ArrowLeft":
newIndex = (index - 1 + tabs.length) % tabs.length;
break;
case "Home":
newIndex = 0;
break;
case "End":
newIndex = tabs.length - 1;
break;
default:
return;
}
tabs[newIndex].focus();
activateTab(tabs[newIndex]);
e.preventDefault();
});Debugging Tips
// Log what screen reader sees
function logAccessibleName(element) {
const computed = window.getComputedStyle(element);
console.log({
role: element.getAttribute("role") || element.tagName,
name:
element.getAttribute("aria-label") ||
element.getAttribute("aria-labelledby") ||
element.textContent,
state: {
expanded: element.getAttribute("aria-expanded"),
selected: element.getAttribute("aria-selected"),
checked: element.getAttribute("aria-checked"),
disabled: element.disabled,
},
visible: computed.display !== "none" && computed.visibility !== "hidden",
});
}Best Practices
Do's
Test with actual screen readers - Not just simulators
Use semantic HTML first - ARIA is supplemental
Test in browse and focus modes - Different experiences
Verify focus management - Especially for SPAs
Test keyboard only first - Foundation for SR testing
Don'ts
Don't assume one SR is enough - Test multiple
Don't ignore mobile - Growing user base
Don't test only happy path - Test error states
Don't skip dynamic content - Most common issues
Don't rely on visual testing - Different experience
Files
- ATTRIBUTION.mdAdded by AutoGineer1011 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md6.3 KiB
- references/jaws-talkback.md1.7 KiB
- references/nvda.md2.3 KiB
- references/voiceover-ios.md1.3 KiB
- references/voiceover.md2.5 KiB
Requirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Seth Hobson
- Publisher
- Seth Hobson (Community)
- Source
- wshobson/agents · plugins/accessibility-compliance/skills/screen-reader-testing · commit 4bde316
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Seth Hobson or Seth Hobson.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download screen-reader-testing.zip