core accessibility principles for modern frameworks

Testing with NVDA & VoiceOver in a Dev Workflow

Automated tools find missing attributes. They cannot tell you that a form reads as "edit, blank, edit, blank" or that your carefully written status message arrives four seconds after the user has moved on. Those findings require listening — and the reason most teams never do is not hostility, it is that nobody showed them the eight commands that make a screen reader usable for testing.

This guide is that introduction: what to install, the commands to learn first, a repeatable ten-minute script, and how to write up what you hear. It is the practical companion to Screen Reader Compatibility Testing.

WCAG Success Criteria Addressed (verified by listening):

  • 1.3.1 Info and Relationships
  • 2.4.3 Focus Order
  • 3.3.2 Labels or Instructions
  • 4.1.2 Name, Role, Value
  • 4.1.3 Status Messages
Which screen reader to test with, and why Three testing environments with their reach and cost. NVDA with Firefox or Chrome on Windows is free and represents the largest share of desktop screen reader use, so it is the default choice. VoiceOver with Safari on macOS is built in and is the only way to test the Safari and WebKit combination. VoiceOver on iOS covers the mobile gesture model, which desktop testing does not exercise at all. A note says testing with one reader catches most issues and testing with none catches none. NVDA + Firefox Windows · free largest desktop share strict about ARIA catches most issues start here VoiceOver + Safari macOS · built in only way to test WebKit different rotor model forgiving of loose ARIA second pass VoiceOver on iOS gesture navigation no Tab key at all exposes touch targets and reading order before mobile release One reader, used regularly, finds far more than three readers used once a year — pick the one on the machine you have.

Prerequisites

  • Windows with NVDA installed, or macOS with VoiceOver (already present — Cmd+F5 toggles it).
  • Headphones, which make this dramatically less disruptive in a shared office.
  • A page you built recently, so the mismatch between what you intended and what you hear is informative.

Learn Eight Commands, Not Eighty

Screen readers have hundreds of shortcuts. Testing needs a handful, and the rest can wait until you need them.

Implementation Guidelines:

  • Learn the modifier first: NVDA uses Insert (or CapsLock in laptop mode); VoiceOver uses Ctrl+Option, written VO.
  • Practise stopping speech before anything else — Ctrl in NVDA, Ctrl in VoiceOver. Being unable to stop the torrent is what makes first attempts miserable.
  • Use browse mode (NVDA's default on a page) for reading and forms mode for typing; NVDA switches automatically, and Insert+Space toggles it manually.
  • On macOS, turn on "VoiceOver can be controlled with the keyboard" and learn the rotor (VO+U) before anything else — it is where headings, landmarks and links live.
NVDA                             VoiceOver (VO = Ctrl+Option)
Ctrl              stop speech    Ctrl                stop speech
Down arrow        read next      VO+Right            read next
H / D / K         heading /      VO+U                rotor: headings,
                  landmark /                          landmarks, links
                  link
Tab               next control   Tab                 next control
Insert+F7         elements list  VO+U then arrows    element lists
Insert+Down       read all       VO+A                read all

A Ten-Minute Script You Can Repeat

An unstructured listen produces vague impressions. A fixed script produces findings you can act on, and it is short enough to run before every pull request that touches UI.

A repeatable ten-minute screen reader pass Five steps with the question each answers. Read the page top to bottom and ask whether the order makes sense. Jump by landmark and ask whether every region is named and distinct. Jump by heading and ask whether the outline reads like a table of contents. Tab through every control and ask whether each has a name, a role and a state. Finally exercise the dynamic behaviour and ask whether changes are announced once, politely, without moving focus. 1 · Read all, top to bottom Does the reading order match the visual order? Is anything read twice, or not at all? 2 · Jump by landmark Is every region named? Are two entries reading "navigation"? 3 · Jump by heading Does the outline sound like a table of contents, with no skipped levels? 4 · Tab every control Name, role, state — all three, on every stop. Any "button" with no name is a finding. 5 · Exercise the dynamic parts Open a dialog, submit a form, filter a list. Announced once? Focus still sensible?

Implementation Guidelines:

  • Run the five steps in order; each one depends on the previous being sane.
  • Write down the exact words you hear, not your interpretation. "Announces 'button'" is a finding; "the button is broken" is not.
  • Test one page per session at first. Ten focused minutes beat an hour of frustrated wandering.
  • Repeat the same script after fixing, so you can confirm the change rather than assuming it.

Know What Each Reader Gets Right

NVDA and VoiceOver disagree, and the disagreement is informative: NVDA is stricter about ARIA, VoiceOver is more forgiving and more idiosyncratic about ordering.

Implementation Guidelines:

  • Treat NVDA's behaviour as the stricter standard: if something works there it usually works elsewhere, and if it does not, the markup is genuinely ambiguous.
  • Do not "fix" for one reader with a hack that breaks the other. If two readers disagree, the underlying semantics are usually wrong.
  • Remember browser pairing: NVDA with Firefox or Chrome, VoiceOver with Safari. Cross-pairings exist but produce results real users rarely see.
  • Check mobile separately. iOS VoiceOver has no Tab key, so a control reachable only by tabbing is unreachable there.

Report What You Heard, Not What You Assume

A useful bug report from a listening session contains the transcript. It is what turns "the modal is not accessible" into a fix someone can make.

Implementation Guidelines:

  • Quote the announcement verbatim, including the role and state words.
  • State what you expected to hear, so the gap is explicit.
  • Include the reader, browser and OS versions — behaviour changes between releases.
  • Attach the sequence of keys you pressed, so the finding is reproducible by someone who has never used the reader.
Reader: NVDA 2026.1 + Firefox 141 (Windows 11)
Steps:  Tab to "Filters", press Enter, Tab twice
Heard:  "button" … "button" … "checkbox not checked"
Expect: "Filters, button, collapsed" … "Framework, React, checkbox not checked"
Issue:  The disclosure has no accessible name or state, and the checkbox
        group is not wrapped in a fieldset, so its legend is never announced.
Two bug reports from the same listening session A comparison of report quality. The vague report says the modal is not accessible with a screen reader, which gives the developer nothing to reproduce or verify. The useful report names the reader, browser and operating system, lists the exact key presses, quotes what was heard, states what was expected, and names the likely cause — a missing accessible name and an unwrapped checkbox group. Vague "The modal is not accessible with a screen reader." Not reproducible, not verifiable, and impossible to close with any confidence. Useful Reader, browser, OS versions Exact key presses to reproduce Heard: "button … button" Expected: "Filters, button, collapsed" Likely cause named Fixable, and verifiable after the fix

How to Verify

  • Fix and re-listen. Run the same five steps after the change; the transcript should now match the expectation you wrote down.
  • Cross-reader check. Confirm the fix in both NVDA and VoiceOver where the finding involved ARIA — agreement across readers is a good sign the semantics are right.
  • Automated backstop. Add a jest-axe or Playwright assertion for anything mechanical you found, so it cannot regress — see Component Testing with jest-axe.
  • Keyboard-only pass. Repeat with the screen reader off; some findings are focus bugs wearing an announcement costume.
  • Mobile pass. For anything touch-related, repeat on iOS VoiceOver, where the gesture model exposes different problems.

Common Accessibility Mistakes

  • Testing only with the screen reader you find easiest. VoiceOver's tolerance hides markup problems NVDA would report immediately.
  • Fixing until the reader says something. The goal is a sensible announcement, not any announcement — "button button" is speech, not success.
  • Treating a screen reader as an assistive-technology simulator. It reflects one user's configuration; real users customise verbosity, speed and rotor heavily.
  • Skipping the "read all" step. It is the fastest way to find content that is duplicated, skipped or in the wrong order.
  • Reporting impressions instead of transcripts. Nobody can fix "it sounds confusing".
  • Testing once, at the end. The findings arrive too late to influence the design, which is where most of them originate.

Conclusion

Fifteen minutes with a screen reader tells you things no scanner can: whether the reading order matches the design, whether your announcements arrive at a useful moment, whether a control's name means anything out of context. Learn eight commands, run the same five-step script every time, quote what you hear, and start with NVDA if you have a choice. It is not a substitute for testing with actual screen reader users — nothing is — but it is the difference between shipping a page you have listened to and shipping one you have only looked at.

One habit makes this stick better than any tooling: run the five-step script on your own work before anyone else sees it. Findings discovered by the person who wrote the component get fixed in minutes, while the same finding routed through a ticket costs a context switch on both sides and often arrives after the design has hardened. Fifteen minutes at the end of a feature, on the branch, is the cheapest accessibility process most teams will ever adopt — and it is the one that changes how the next component gets written.

Frequently Asked Questions

Do I need to be good at using a screen reader? No, and it is worth being explicit that you never will be as fluent as a daily user. That is fine: the goal is to hear what your page produces, not to simulate expertise. Most findings surface in the first two minutes of any competent listening pass.

Is JAWS worth testing with too? It has substantial enterprise use and it is commercial. If your audience is enterprise, add it; otherwise NVDA covers a similar Windows behaviour space for free. The forty-minute JAWS demo mode is enough for occasional verification.

Can browser extensions replace a real screen reader? Accessibility tree inspectors and simulators are useful for debugging names and roles, and they do not tell you what a page sounds like — the pacing, the interruptions, the repetition. Use them alongside a real reader, not instead of one.

How do I test in CI? You cannot automate what a screen reader announces in any practical way. What you can automate is the underlying data: assert accessible names with Testing Library's role queries, assert live-region text, assert focus after transitions. Those cover the mechanical half — see testing ARIA live regions with Jest and Testing Library.

What if I have no Windows machine? Start with VoiceOver on macOS and iOS; it is already installed. Add NVDA in a Windows virtual machine when you can, since it is stricter and represents a larger share of desktop use — but a VoiceOver-only habit is far better than none.