Screen Reader Testing Checklist
A structured checklist for verifying screen reader accessibility with Speakable. Work through each category to catch common issues before they reach users. This complements, but does not replace, manual testing with real assistive technology.
Navigation
All landmarks have accessible names
Each nav, aside, and section should have a unique aria-label so screen reader users can distinguish them in the landmarks list.
speakable page.html -f audit | grep "landmark"
Heading hierarchy is sequential (no skipping levels)
Headings should follow a logical order (h1 → h2 → h3). Skipping from h1 to h3 confuses users who navigate by heading level.
speakable page.html -f audit
Skip navigation link is present and works
A visually hidden "Skip to content" link should be the first focusable element, letting keyboard users bypass repeated navigation.
speakable page.html -f text -s voiceover --selector "a[href='#main']"
Tab order matches visual order
Interactive elements should receive focus in the same order they appear visually. Avoid positive tabindex values.
speakable page.html -f json | node -e "const d=require('fs').readFileSync('/dev/stdin','utf8');const j=JSON.parse(d);console.log(j.filter(n=>n.focusable).map(n=>n.name))"Forms
All inputs have associated labels
Every form control needs a programmatically associated label via for/id, wrapping, or aria-labelledby. Placeholders are not labels.
speakable form.html -f audit
Required fields are announced
Inputs with the required attribute or aria-required="true" should be announced as required by screen readers.
speakable form.html -f text -s nvda --selector "input[required]"
Error messages are linked to inputs
When validation fails, error messages should be associated via aria-describedby so they're announced when the input receives focus.
speakable form.html -f text -s jaws --selector "[aria-invalid]"
Fieldsets group related controls
Radio buttons and checkbox groups should be wrapped in a fieldset with a legend to provide group context.
speakable form.html -f text --selector "fieldset"
Dynamic Content
Status messages use aria-live regions
Content that updates dynamically (success messages, counters) should be in an aria-live="polite" region so screen readers announce changes.
Manual verification required: check source code directly.
Loading states communicate progress
Spinners and loading indicators should use role="progressbar" or aria-busy="true" to inform assistive technology that content is loading.
Manual verification required: check source code directly.
Toast notifications use role="alert"
Transient notifications should use role="alert" or aria-live="assertive" to interrupt the user and announce immediately.
speakable toast.html -f text -s all
Media
Images have alt text (or are decorative)
Informative images need descriptive alt text. Decorative images should use alt="" to be hidden from screen readers.
speakable page.html -f audit | grep "image"
Videos have captions/transcripts
Video content must have synchronized captions for deaf users and transcripts for deafblind users.
Manual verification required: check source code directly.
Icons used as buttons have accessible names
Icon buttons without visible text must have aria-label or visually hidden text to communicate their purpose.
speakable page.html -f text --selector "button"
Tables
Data tables have headers
Use <th> elements with proper scope attributes so screen readers can associate data cells with their column or row headers.
speakable table.html -f text -s nvda --selector "table"
Caption or aria-label identifies table purpose
Every data table should have a <caption> or aria-label that describes what data the table presents.
speakable table.html -f audit
Layout tables don't use table semantics
Tables used purely for layout should have role="presentation" to prevent screen readers from announcing table structure.
Manual verification required: check source code directly.
Custom Widgets
Custom controls have correct ARIA roles
Non-native widgets (tabs, accordions, menus) must have appropriate ARIA roles so screen readers announce their type correctly.
speakable widget.html -f text -s all
States are communicated (expanded, checked, etc.)
Dynamic states like aria-expanded, aria-checked, and aria-selected must update when the user interacts with the widget.
speakable widget.html -f json | grep "state"
Keyboard interaction follows ARIA patterns
Custom widgets should follow the ARIA Authoring Practices keyboard patterns (arrow keys for tabs, Enter/Space for buttons, etc.).
Manual verification required: check source code directly.
Suggested workflow
Start with speakable page.html -f audit to get an overview of issues, then use targeted selectors to verify specific elements. Integrate into your CI/CD pipeline to catch regressions automatically.
Related Pages
Testing Strategy
Learn how to build a comprehensive accessibility testing strategy combining automated and manual approaches.
CI/CD Integration
Set up Speakable in your CI pipeline to catch accessibility regressions before they ship.
Testing Ecosystem
See how Speakable fits alongside other accessibility testing tools like axe-core and Pa11y.
Common Mistakes
Real-world HTML patterns that break screen reader experiences and how to fix them.