<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: R3TICULAR</title>
    <description>The latest articles on DEV Community by R3TICULAR (@r3ticular).</description>
    <link>https://dev.to/r3ticular</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3877394%2Fedb1cc1d-750c-4363-b783-d7cc7b4da306.jpeg</url>
      <title>DEV Community: R3TICULAR</title>
      <link>https://dev.to/r3ticular</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/r3ticular"/>
    <language>en</language>
    <item>
      <title>Devs, How Are You Testing NVDA, JAWS, VoiceOver, and Narrator Without Owning Three Operating Systems?</title>
      <dc:creator>R3TICULAR</dc:creator>
      <pubDate>Sat, 20 Jun 2026 19:42:38 +0000</pubDate>
      <link>https://dev.to/r3ticular/devs-how-are-you-testing-nvda-jaws-voiceover-and-narrator-without-owning-three-operating-2c8m</link>
      <guid>https://dev.to/r3ticular/devs-how-are-you-testing-nvda-jaws-voiceover-and-narrator-without-owning-three-operating-2c8m</guid>
      <description>&lt;p&gt;Most Teams Only Test One Screen Reader. Here’s the Problem With That.&lt;/p&gt;

&lt;p&gt;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?&lt;/p&gt;

&lt;p&gt;For most teams, the answer is one.&lt;/p&gt;

&lt;p&gt;Not because they don’t care about accessibility. Not because they don’t want to test more thoroughly.&lt;/p&gt;

&lt;p&gt;Because the tooling ecosystem makes it surprisingly difficult.&lt;/p&gt;

&lt;p&gt;The Cross-Platform Screen Reader Problem&lt;/p&gt;

&lt;p&gt;Today, testing screen reader accessibility typically means testing across multiple screen readers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NVDA (Windows only)&lt;/li&gt;
&lt;li&gt;JAWS (Windows only, paid license)&lt;/li&gt;
&lt;li&gt;VoiceOver (macOS and iOS only)&lt;/li&gt;
&lt;li&gt;Narrator (Windows only)&lt;/li&gt;
&lt;li&gt;and honestly more like Orca ChromeVox and whatnot &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The challenge is obvious:&lt;/p&gt;

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

&lt;p&gt;As a result, accessibility bugs often survive until late QA cycles—or worse, production.&lt;/p&gt;

&lt;p&gt;The feedback loop is broken by platform lock-in.&lt;/p&gt;

&lt;p&gt;The Hidden Problem: Screen Readers Don’t Agree&lt;/p&gt;

&lt;p&gt;Many developers assume that if a component works in one screen reader, it will behave similarly everywhere else.&lt;/p&gt;

&lt;p&gt;In reality, screen readers frequently announce the same element differently.&lt;/p&gt;

&lt;p&gt;Consider a simple button:&lt;/p&gt;

&lt;p&gt;Submit form&lt;/p&gt;

&lt;p&gt;so Using Speakable like so:&lt;/p&gt;

&lt;p&gt;npx @reticular/speakable analyze button.html --renderer all&lt;/p&gt;

&lt;p&gt;We get this output: &lt;/p&gt;

&lt;p&gt;── VoiceOver ──&lt;/p&gt;

&lt;p&gt;"Submit form, button"&lt;/p&gt;

&lt;p&gt;── NVDA ──&lt;/p&gt;

&lt;p&gt;"button, Submit form"&lt;/p&gt;

&lt;p&gt;── JAWS ──&lt;/p&gt;

&lt;p&gt;"Submit form button"&lt;/p&gt;

&lt;p&gt;── Narrator ──&lt;/p&gt;

&lt;p&gt;"Submit form, button, to activate press Enter"&lt;/p&gt;

&lt;p&gt;At first glance these differences may seem minor.&lt;/p&gt;

&lt;p&gt;But announcement order, punctuation handling, verbosity, and interaction hints all influence how users understand and navigate interfaces.&lt;/p&gt;

&lt;p&gt;A component can feel perfectly clear in one screen reader while becoming noticeably more confusing in another.&lt;/p&gt;

&lt;p&gt;Without cross-testing, these differences remain invisible.&lt;/p&gt;

&lt;p&gt;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.&lt;/p&gt;

&lt;p&gt;Instead of launching four separate screen readers across multiple operating systems, Speakable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Parses your HTML into an accessibility tree&lt;/li&gt;
&lt;li&gt;Interprets roles, names, states, and properties&lt;/li&gt;
&lt;li&gt;Runs that information through screen-reader-specific renderers&lt;/li&gt;
&lt;li&gt;Shows how each screen reader is likely to announce the content&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The goal isn’t to replace manual testing.&lt;/p&gt;

&lt;p&gt;The goal is to make accessibility feedback available during development instead of only during QA.&lt;/p&gt;

&lt;p&gt;Think of it as:&lt;/p&gt;

&lt;p&gt;Speakable + Screen Readers &amp;gt; Screen Readers Alone&lt;/p&gt;

&lt;p&gt;Speakable helps catch issues between commits.&lt;/p&gt;

&lt;p&gt;Real screen readers still provide final validation before release.&lt;/p&gt;

&lt;p&gt;Catching Accessibility Regressions with Semantic Diff&lt;/p&gt;

&lt;p&gt;One of the hardest accessibility problems isn’t finding bugs.&lt;/p&gt;

&lt;p&gt;It’s preventing regressions.&lt;/p&gt;

&lt;p&gt;A seemingly harmless markup change can completely alter what gets announced.&lt;/p&gt;

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

&lt;p&gt;Before might have read:&lt;br&gt;
"Search, edit text"&lt;/p&gt;

&lt;p&gt;but after markup changed and it reads:&lt;br&gt;
"edit text"&lt;/p&gt;

&lt;p&gt;Suddenly you’ve lost the accessible name (oh god is this a lawsuit?).&lt;/p&gt;

&lt;p&gt;The visual UI may look identical.&lt;/p&gt;

&lt;p&gt;The accessibility experience changed significantly.&lt;/p&gt;

&lt;p&gt;This makes semantic diff especially useful inside CI pipelines.&lt;/p&gt;

&lt;p&gt;That means pull requests can surface accessibility-impacting changes automatically (we love regression catchers).&lt;/p&gt;

&lt;p&gt;Full Accessibility Audits from the Command Line&lt;/p&gt;

&lt;p&gt;Speakable also provides accessibility auditing without requiring browser DevTools.&lt;/p&gt;

&lt;p&gt;The audit engine can identify issues such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Missing labels&lt;/li&gt;
&lt;li&gt;Broken ARIA references&lt;/li&gt;
&lt;li&gt;Focusable elements without accessible names&lt;/li&gt;
&lt;li&gt;Roles missing required properties&lt;/li&gt;
&lt;li&gt;Invalid accessibility relationships&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This creates a fast feedback loop directly from the terminal.&lt;/p&gt;

&lt;p&gt;No browser setup required.&lt;/p&gt;

&lt;p&gt;No navigating through multiple inspection panels.&lt;/p&gt;

&lt;p&gt;Just run the audit and review the report.&lt;/p&gt;

&lt;p&gt;Static Analysis Isn’t Enough&lt;/p&gt;

&lt;p&gt;Modern web applications are increasingly dynamic.&lt;/p&gt;

&lt;p&gt;Accessibility issues often emerge only after user interaction.&lt;/p&gt;

&lt;p&gt;Examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Opening a modal&lt;/li&gt;
&lt;li&gt;Filtering a combobox&lt;/li&gt;
&lt;li&gt;Triggering a live region update&lt;/li&gt;
&lt;li&gt;Moving focus between components&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Static HTML analysis can’t fully capture those behaviors.&lt;/p&gt;

&lt;p&gt;That’s why Speakable 1.4 introduced runtime accessibility analysis. allowing you to do things like this: &lt;/p&gt;

&lt;p&gt;import { createRuntimeEngine } from '@reticular/speakable/runtime';&lt;/p&gt;

&lt;p&gt;const engine = createRuntimeEngine(document);&lt;/p&gt;

&lt;p&gt;engine.start();&lt;/p&gt;

&lt;p&gt;engine.interact('click', '#open-modal');&lt;/p&gt;

&lt;p&gt;engine.interact('tab');&lt;/p&gt;

&lt;p&gt;const timeline = engine.getTimeline();&lt;/p&gt;

&lt;p&gt;The resulting timeline shows accessibility-relevant events such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus movement&lt;/li&gt;
&lt;li&gt;Role announcements&lt;/li&gt;
&lt;li&gt;ARIA state changes&lt;/li&gt;
&lt;li&gt;Live region updates&lt;/li&gt;
&lt;li&gt;Modal activation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This helps surface problems that traditional linting and static analysis tools often miss.&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus trapped incorrectly&lt;/li&gt;
&lt;li&gt;Focus escaping a modal&lt;/li&gt;
&lt;li&gt;Live regions that never announce updates&lt;/li&gt;
&lt;li&gt;Comboboxes that fail to communicate filtered results&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Accessibility Checks Inside AI Coding Assistants&lt;/p&gt;

&lt;p&gt;Another challenge with accessibility tooling is context switching.&lt;/p&gt;

&lt;p&gt;Developers frequently jump between:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Editor&lt;/li&gt;
&lt;li&gt;Browser&lt;/li&gt;
&lt;li&gt;Accessibility inspector&lt;/li&gt;
&lt;li&gt;Screen reader&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Well with this new wave of MCP servers, Speakable can also run as an MCP server. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;npx @reticular/speakable-mcp&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Storybook Support for Component Libraries&lt;/p&gt;

&lt;p&gt;For teams maintaining design systems or component libraries, Speakable can analyze Storybook deployments directly.&lt;/p&gt;

&lt;p&gt;Point Speakable at a running Storybook instance and it will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crawl stories&lt;/li&gt;
&lt;li&gt;Analyze rendered HTML&lt;/li&gt;
&lt;li&gt;Generate accessibility reports&lt;/li&gt;
&lt;li&gt;Produce component-level findings&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Protected environments are supported as well through authentication headers, making it usable for internal Storybook deployments behind VPNs or enterprise authentication systems.&lt;/p&gt;

&lt;p&gt;For design system teams, this creates a scalable way to evaluate accessibility across hundreds of components.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;npm&lt;/p&gt;

&lt;p&gt;@reticular/speakable&lt;/p&gt;

&lt;p&gt;Website&lt;/p&gt;

&lt;p&gt;&lt;a href="https://getspeakable.dev" rel="noopener noreferrer"&gt;https://getspeakable.dev&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;GitHub&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/R3TICULAR/AnnounceKit" rel="noopener noreferrer"&gt;https://github.com/R3TICULAR/AnnounceKit&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Discord&lt;/p&gt;

&lt;p&gt;&lt;a href="https://discord.gg/uSKJUEgdR" rel="noopener noreferrer"&gt;https://discord.gg/uSKJUEgdR&lt;/a&gt;&lt;/p&gt;

</description>
      <category>screenreadertesting</category>
      <category>nvda</category>
      <category>voiceover</category>
      <category>accessibilitytesting</category>
    </item>
    <item>
      <title>You’re Probably Not Testing Accessibility the Way Users Experience It</title>
      <dc:creator>R3TICULAR</dc:creator>
      <pubDate>Mon, 13 Apr 2026 22:41:48 +0000</pubDate>
      <link>https://dev.to/r3ticular/youre-probably-not-testing-accessibility-the-way-users-experience-it-46em</link>
      <guid>https://dev.to/r3ticular/youre-probably-not-testing-accessibility-the-way-users-experience-it-46em</guid>
      <description>&lt;p&gt;Most frontend developers today use tools like Axe, WAVE, or Lighthouse to test accessibility.&lt;/p&gt;

&lt;p&gt;And that’s a good start.&lt;/p&gt;

&lt;p&gt;But there’s a gap that these tools don’t really cover:&lt;/p&gt;

&lt;p&gt;They don’t tell you what a screen reader user actually hears.&lt;/p&gt;

&lt;p&gt;The Problem: Accessibility ≠ Announcement&lt;/p&gt;

&lt;p&gt;Let’s take a simple example:&lt;/p&gt;



&lt;p&gt;From a rule-based perspective, this passes:&lt;br&gt;
-It has an accessible name&lt;br&gt;
-It uses a semantic element&lt;/p&gt;

&lt;p&gt;But what does a screen reader actually announce?&lt;br&gt;&lt;br&gt;
NVDA: “Submit Payment, button”&lt;br&gt;
VoiceOver: “Submit Payment, button”&lt;br&gt;
JAWS: “Submit Payment, button”&lt;/p&gt;

&lt;p&gt;So far, so good.&lt;/p&gt;

&lt;p&gt;Now let’s tweak it slightly:&lt;/p&gt;

&lt;p&gt;Submit&lt;/p&gt;

&lt;p&gt;This might still pass some basic checks.&lt;/p&gt;

&lt;p&gt;But a screen reader might announce:&lt;/p&gt;

&lt;p&gt;“Submit”&lt;/p&gt;

&lt;p&gt;Not:&lt;/p&gt;

&lt;p&gt;“Submit, button”&lt;/p&gt;

&lt;p&gt;That’s a completely different experience.&lt;/p&gt;

&lt;p&gt;The Real Pain: Testing Screen Readers Is Hard&lt;/p&gt;

&lt;p&gt;If you’ve ever tried to properly test this, you know the workflow:&lt;/p&gt;

&lt;p&gt;Install NVDA (Windows),&lt;br&gt;
Maybe use JAWS (paid, also Windows)&lt;br&gt;
Use VoiceOver (macOS),&lt;br&gt;
Navigate everything with a keyboard&lt;br&gt;
Listen carefully to announcements&lt;br&gt;
Repeat across browsers and flows&lt;/p&gt;

&lt;p&gt;It works—but it’s pretty slow, manual, hard to automate, and OS dependent &lt;/p&gt;

&lt;p&gt;In practice, what happens is:&lt;br&gt;
Run Axe/Lighthouse → fix obvious issues then&lt;br&gt;
Do minimal screen reader testing (if any), then&lt;br&gt;
Ship- badaboom.&lt;/p&gt;

&lt;p&gt;The problem?&lt;/p&gt;

&lt;p&gt;Most accessibility issues that affect real users show up in how things are announced, not just whether rules pass.&lt;/p&gt;

&lt;p&gt;A Missing Layer in the Tooling&lt;/p&gt;

&lt;p&gt;What’s missing is something in between:&lt;br&gt;
Not just rule-based linting&lt;br&gt;
Not full manual screen reader testing but-&lt;/p&gt;

&lt;p&gt;A way to preview how your markup will be interpreted by assistive technologies&lt;/p&gt;

&lt;p&gt;Recently in being fed up with this, I started building a tool to help with this exact problem:&lt;br&gt;
👉 getspeakable.dev&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1zidyv0q7annvmoa5we.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy1zidyv0q7annvmoa5we.png" alt="Image displaying the analyzer tool at getspeakable.dev" width="800" height="452"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can paste in HTML and see predicted announcements for:&lt;br&gt;
    • NVDA&lt;br&gt;
    • JAWS&lt;br&gt;
    • VoiceOver&lt;/p&gt;

&lt;p&gt;For example:&lt;/p&gt;

&lt;p&gt;🔍&lt;/p&gt;

&lt;p&gt;Might produce something like:&lt;/p&gt;

&lt;p&gt;“button”&lt;/p&gt;

&lt;p&gt;Instead of:&lt;/p&gt;

&lt;p&gt;“Search, button”&lt;/p&gt;

&lt;p&gt;Which immediately tells you:&lt;br&gt;
the element has no accessible name&lt;/p&gt;

&lt;p&gt;Noted that, this isn’t a replacement for real screen reader testing.&lt;/p&gt;

&lt;p&gt;Instead, it fits earlier in the process alongside linting (Axe &amp;amp; lighthouse) tools, then using speakable for audible authentication/regression, and the n manual screen reader testing to validate real user experience.&lt;/p&gt;

&lt;p&gt;Catching them earlier is significantly cheaper than fixing them later.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>api</category>
    </item>
  </channel>
</rss>
