DEV Community

Cover image for Devs, How Are You Testing NVDA, JAWS, VoiceOver, and Narrator Without Owning Three Operating Systems?
R3TICULAR
R3TICULAR

Posted on

Devs, How Are You Testing NVDA, JAWS, VoiceOver, and Narrator Without Owning Three Operating Systems?

Most Teams Only Test One Screen Reader. Here’s the Problem With That.

If you’re a frontend developer who cares about accessibility and or has to do the laborious task of screen reader testing for your web experiences, how many screen readers do you actually test with before shipping?

For most teams, the answer is one.

Not because they don’t care about accessibility. Not because they don’t want to test more thoroughly.

Because the tooling ecosystem makes it surprisingly difficult.

The Cross-Platform Screen Reader Problem

Today, testing screen reader accessibility typically means testing across multiple screen readers:

  • NVDA (Windows only)
  • JAWS (Windows only, paid license)
  • VoiceOver (macOS and iOS only)
  • Narrator (Windows only)
  • and honestly more like Orca ChromeVox and whatnot

The challenge is obvious:

  • macOS developers can test VoiceOver natively
  • Windows developers can test NVDA, JAWS, or Narrator
  • Most teams don’t maintain accessibility testing environments across every operating system
  • Almost nobody manually validates every component against all four screen readers during day-to-day development

As a result, accessibility bugs often survive until late QA cycles—or worse, production.

The feedback loop is broken by platform lock-in.

The Hidden Problem: Screen Readers Don’t Agree

Many developers assume that if a component works in one screen reader, it will behave similarly everywhere else.

In reality, screen readers frequently announce the same element differently.

Consider a simple button:

Submit form

so Using Speakable like so:

npx @reticular/speakable analyze button.html --renderer all

We get this output:

── VoiceOver ──

"Submit form, button"

── NVDA ──

"button, Submit form"

── JAWS ──

"Submit form button"

── Narrator ──

"Submit form, button, to activate press Enter"

At first glance these differences may seem minor.

But announcement order, punctuation handling, verbosity, and interaction hints all influence how users understand and navigate interfaces.

A component can feel perfectly clear in one screen reader while becoming noticeably more confusing in another.

Without cross-testing, these differences remain invisible.

Now what I found Speakable does as a CLI and MCP tool is that it predicts what multiple screen readers will announce from a piece of HTML.

Instead of launching four separate screen readers across multiple operating systems, Speakable:

  1. Parses your HTML into an accessibility tree
  2. Interprets roles, names, states, and properties
  3. Runs that information through screen-reader-specific renderers
  4. Shows how each screen reader is likely to announce the content

The goal isn’t to replace manual testing.

The goal is to make accessibility feedback available during development instead of only during QA.

Think of it as:

Speakable + Screen Readers > Screen Readers Alone

Speakable helps catch issues between commits.

Real screen readers still provide final validation before release.

Catching Accessibility Regressions with Semantic Diff

One of the hardest accessibility problems isn’t finding bugs.

It’s preventing regressions.

A seemingly harmless markup change can completely alter what gets announced.

found that Speakable includes a semantic diff engine as well where instead of comparing raw HTML, it compares accessibility announcements. i.e

Before might have read:
"Search, edit text"

but after markup changed and it reads:
"edit text"

Suddenly you’ve lost the accessible name (oh god is this a lawsuit?).

The visual UI may look identical.

The accessibility experience changed significantly.

This makes semantic diff especially useful inside CI pipelines.

That means pull requests can surface accessibility-impacting changes automatically (we love regression catchers).

Full Accessibility Audits from the Command Line

Speakable also provides accessibility auditing without requiring browser DevTools.

The audit engine can identify issues such as:

  • Missing labels
  • Broken ARIA references
  • Focusable elements without accessible names
  • Roles missing required properties
  • Invalid accessibility relationships

This creates a fast feedback loop directly from the terminal.

No browser setup required.

No navigating through multiple inspection panels.

Just run the audit and review the report.

Static Analysis Isn’t Enough

Modern web applications are increasingly dynamic.

Accessibility issues often emerge only after user interaction.

Examples:

  • Opening a modal
  • Filtering a combobox
  • Triggering a live region update
  • Moving focus between components

Static HTML analysis can’t fully capture those behaviors.

That’s why Speakable 1.4 introduced runtime accessibility analysis. allowing you to do things like this:

import { createRuntimeEngine } from '@reticular/speakable/runtime';

const engine = createRuntimeEngine(document);

engine.start();

engine.interact('click', '#open-modal');

engine.interact('tab');

const timeline = engine.getTimeline();

The resulting timeline shows accessibility-relevant events such as:

  • Focus movement
  • Role announcements
  • ARIA state changes
  • Live region updates
  • Modal activation

This helps surface problems that traditional linting and static analysis tools often miss.

For example:

  • Focus trapped incorrectly
  • Focus escaping a modal
  • Live regions that never announce updates
  • Comboboxes that fail to communicate filtered results

Accessibility Checks Inside AI Coding Assistants

Another challenge with accessibility tooling is context switching.

Developers frequently jump between:

  • Editor
  • Browser
  • Accessibility inspector
  • Screen reader
  • Documentation

Well with this new wave of MCP servers, Speakable can also run as an MCP server.

npx @reticular/speakable-mcp

Storybook Support for Component Libraries

For teams maintaining design systems or component libraries, Speakable can analyze Storybook deployments directly.

Point Speakable at a running Storybook instance and it will:

  • Crawl stories
  • Analyze rendered HTML
  • Generate accessibility reports
  • Produce component-level findings

Protected environments are supported as well through authentication headers, making it usable for internal Storybook deployments behind VPNs or enterprise authentication systems.

For design system teams, this creates a scalable way to evaluate accessibility across hundreds of components.

Links

npm

@reticular/speakable

Website

https://getspeakable.dev

GitHub

https://github.com/R3TICULAR/AnnounceKit

Discord

https://discord.gg/uSKJUEgdR

Top comments (0)