<?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: a11ySolutions</title>
    <description>The latest articles on DEV Community by a11ySolutions (@a11ysolutions).</description>
    <link>https://dev.to/a11ysolutions</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%2F3891044%2Ffeba947e-b8c0-48de-be8f-0c3b713945e2.png</url>
      <title>DEV Community: a11ySolutions</title>
      <link>https://dev.to/a11ysolutions</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/a11ysolutions"/>
    <language>en</language>
    <item>
      <title>Your Website Has an Index. AI Agents Can't Navigate Without It.</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Fri, 10 Jul 2026 13:36:21 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/your-website-has-an-index-ai-agents-cant-navigate-without-it-4kkj</link>
      <guid>https://dev.to/a11ysolutions/your-website-has-an-index-ai-agents-cant-navigate-without-it-4kkj</guid>
      <description>&lt;p&gt;Try finding one specific fact in a 400-page book with no index. You'll get there eventually, page by page. You'll also waste time, get tired, and maybe give up before you find it.&lt;/p&gt;

&lt;p&gt;With an index, the experience changes completely: check the table of contents, jump to the right chapter, done.&lt;/p&gt;

&lt;p&gt;Web pages have their own index. It's called the accessibility tree, and it's the structure both screen readers and AI agents use to navigate a site. Neither of them sees your rendered layout. They see the tree.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The tree is built from code decisions&lt;/strong&gt;&lt;br&gt;
Every part of the tree maps to something you write:&lt;/p&gt;

&lt;p&gt;Headings give the page a table of contents. A logical &lt;code&gt;h1&lt;/code&gt; to &lt;code&gt;h3&lt;/code&gt; hierarchy tells the user, or the agent, what's on the page and in what order.&lt;/p&gt;

&lt;p&gt;Labels explain what controls do. A button that reads "Submit" in context means nothing out of context. &lt;code&gt;aria-label="Submit booking request"&lt;/code&gt; carries the meaning with it.&lt;/p&gt;

&lt;p&gt;Alt text is the only description of an image that exists in the tree. Empty alt on a meaningful image means the image doesn't exist for anyone reading the tree.&lt;/p&gt;

&lt;p&gt;Link text says where an action leads. "Click here" is a dead end when you can't see the surrounding layout.&lt;/p&gt;

&lt;h2&gt;
  
  
  What happens when the tree is broken
&lt;/h2&gt;

&lt;p&gt;Here's the part that gets oversimplified. A broken tree doesn't always mean the agent fails outright. Often it means the agent brute-forces its way through, and that's worth understanding.&lt;/p&gt;

&lt;p&gt;Without headings, the agent can't jump to the right section. It has to process the entire page to orient itself.&lt;/p&gt;

&lt;p&gt;Without labels, it can't know what a control does. It has to guess and act. Sometimes it catches the mistake and retries; sometimes it never realizes it clicked the wrong thing. Research on web agents documents both behaviors: grounding errors where agents fail to identify the intended element, and agents getting stuck in loops without recovering.&lt;/p&gt;

&lt;p&gt;Without semantic buttons and real links (looking at you, &lt;code&gt;div&lt;/code&gt; with an &lt;code&gt;onclick&lt;/code&gt;), it can't reliably identify what's interactive at all.&lt;/p&gt;

&lt;p&gt;Sometimes the agent still completes the task. But every extra step adds latency, adds compute, and adds error surface: the wrong button, the wrong field, the task that silently ends up half done. Finding the information is not the same as completing the task. And completing it late, with errors, or halfway isn't completing it either.&lt;/p&gt;

&lt;p&gt;Exactly like the book with no index. You might find the page. You arrived late, tired, and with no guarantee you read the right one.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The usual suspects&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The tree almost never breaks for exotic reasons. It breaks on the basics:&lt;/p&gt;

&lt;p&gt;Divs styled to look like buttons, with no role and no keyboard handling. Pages with no heading hierarchy, just styled text. Meaningful images with empty or missing alt attributes. Links with no &lt;code&gt;href&lt;/code&gt;, wired entirely through JavaScript click handlers. Custom form controls that never expose their state.&lt;/p&gt;

&lt;p&gt;Each one is a small decision at code review time. Together they decide whether your site is navigable by anything that isn't a sighted human with a mouse.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is not a new standard&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Nobody needs "AI readiness" guidelines. The spec already exists: semantic HTML, proper heading structure, real labels, real buttons, real links, keyboard operability. It's WCAG, applied to a new class of user.&lt;/p&gt;

&lt;p&gt;Which means teams that already treat accessibility as core engineering practice didn't prepare for AI agents. They built for humans correctly, and the agents inherited the benefit.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>a11y</category>
      <category>webdev</category>
      <category>seo</category>
    </item>
    <item>
      <title>One line of CSS that breaks keyboard accessibility sitewide and two other patterns we keep finding in audits</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Wed, 01 Jul 2026 10:09:18 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/one-line-of-css-that-breaks-keyboard-accessibility-sitewide-and-two-other-patterns-we-keep-finding-4daa</link>
      <guid>https://dev.to/a11ysolutions/one-line-of-css-that-breaks-keyboard-accessibility-sitewide-and-two-other-patterns-we-keep-finding-4daa</guid>
      <description>&lt;p&gt;Last week we ran accessibility audits across multiple sites. Different industries, different tech stacks, different teams.&lt;/p&gt;

&lt;p&gt;The same three problems kept showing up.&lt;/p&gt;

&lt;p&gt;Not similar problems. The exact same patterns, reproduced independently, causing the same failures for keyboard users and screen reader users across every site we reviewed.&lt;/p&gt;

&lt;p&gt;That's what makes these worth documenting. When something appears consistently across unrelated projects, it's not a coincidence, it's an industry-wide gap in how accessibility gets implemented.&lt;/p&gt;

&lt;p&gt;This article covers the three patterns, the exact code behind each one, and the fix. No abstractions.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PATTERN 1 — One line of CSS that removes focus indicators sitewide&lt;/strong&gt;&lt;br&gt;
Heading: The most common keyboard accessibility failure we see: outline: none&lt;/p&gt;

&lt;p&gt;This is the one that surprises people the most, because it's so small.&lt;/p&gt;

&lt;p&gt;A developer adds this somewhere in the global stylesheet, usually to clean up the default browser focus ring, which can look inconsistent across browsers:&lt;/p&gt;

&lt;p&gt;a:focus {&lt;br&gt;
  outline: none;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;button:focus {&lt;br&gt;
  outline: 0;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Sometimes it's scoped to a component. Sometimes it's applied globally. Either way, the result is the same: every keyboard user navigating your site loses their only visual indicator of where they are on the page.&lt;/p&gt;

&lt;p&gt;Tab still works. Focus is still moving. The user just can't see it.&lt;/p&gt;

&lt;p&gt;For someone navigating with a keyboard due to a motor disability, this is the equivalent of removing the cursor from a mouse user's screen. They can keep clicking, but they have no idea where.&lt;/p&gt;

&lt;p&gt;This fails WCAG 2.4.7 (Focus Visible) and WCAG 2.4.11 (Focus Appearance) at the AA level.&lt;/p&gt;

&lt;p&gt;The fix:&lt;br&gt;
Don't remove the outline. Style it instead.&lt;/p&gt;

&lt;p&gt;css&lt;br&gt;
/* Remove this */&lt;br&gt;
a:focus { outline: none; }&lt;br&gt;
button:focus { outline: 0; }&lt;/p&gt;

&lt;p&gt;/* Replace with this */&lt;br&gt;
:focus-visible {&lt;br&gt;
  outline: 2px solid #0057b7;&lt;br&gt;
  outline-offset: 2px;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Using :focus-visible instead of :focus gives you the best of both worlds: the focus indicator appears for keyboard navigation but not for mouse clicks, which is the behavior most design systems want. The browser handles the distinction natively.&lt;/p&gt;

&lt;p&gt;Two things to verify after applying this fix: the outline color meets a 3:1 contrast ratio against the adjacent background (WCAG 1.4.11), and the outline is visible against both light and dark backgrounds if your site uses both.&lt;/p&gt;

&lt;p&gt;One line caused the problem. One rule fixes it sitewide.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PATTERN 2 — Interactive elements built with the wrong HTML that never enter the tab order&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Heading: If it's not natively focusable, keyboard users can't reach it&lt;/p&gt;

&lt;p&gt;This one appears most often in navigation components, menus, toggles, icon buttons, where a developer reaches for a &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; or an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; without an href because it felt like the right container for the visual design.&lt;/p&gt;

&lt;p&gt;Here's a real pattern we documented. A hamburger menu trigger built like this:&lt;/p&gt;

&lt;p&gt;html&lt;br&gt;
&lt;code&gt;&amp;lt;a class="nav-btn js-nav-btn-menu" &lt;br&gt;
   data-toggle="dropdown" &lt;br&gt;
   data-display="static"&amp;gt;&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;&amp;lt;svg width="26" height="26" viewBox="0 0 32 32" &lt;br&gt;
       fill="none" xmlns="http://www.w3.org/2000/svg"&amp;gt;&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;&amp;lt;path d="M1.71436 14.8571H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;&amp;lt;path d="M1.71436 25.1428H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;&amp;lt;path d="M1.71436 4.57141H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
 &lt;code&gt;&amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The problem: an &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; element without an href attribute is not focusable by default. It exists in the DOM, it's visible on screen, it works with a mouse click via JavaScript, but Tab navigation skips it entirely.&lt;/p&gt;

&lt;p&gt;The SVG has no role, no accessible name, no keyboard interaction. A keyboard user cannot open the navigation menu at all. On a mobile-first site where this menu is the primary navigation, that's a complete blocker.&lt;/p&gt;

&lt;p&gt;This fails WCAG 2.1.1 (Keyboard) at the AA level.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
Use a native  element. It's focusable by default, activatable with Enter and Space, and requires no extra ARIA to work correctly:&lt;/p&gt;


&lt;p&gt;html&lt;br&gt;
&lt;code&gt;&amp;lt;button &lt;br&gt;
  class="nav-btn js-nav-btn-menu"&lt;br&gt;
  aria-expanded="false"&lt;br&gt;
  aria-controls="main-nav"&lt;br&gt;
  aria-label="Open navigation menu"&amp;gt;&lt;/code&gt;&lt;br&gt;
  &lt;code&gt;&amp;lt;svg width="26" height="26" viewBox="0 0 32 32" &lt;br&gt;
       fill="none" xmlns="http://www.w3.org/2000/svg" &lt;br&gt;
       aria-hidden="true" focusable="false"&amp;gt;&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;&amp;lt;path d="M1.71436 14.8571H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
   &lt;code&gt;&amp;lt;path d="M1.71436 25.1428H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
    &lt;code&gt;&amp;lt;path d="M1.71436 4.57141H30.2858" stroke="#003680" &lt;br&gt;
          stroke-width="2" stroke-linecap="round"/&amp;gt;&lt;/code&gt;&lt;br&gt;
 &lt;code&gt;&amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;javascript&lt;br&gt;
const navBtn = document.querySelector('.nav-btn');&lt;br&gt;
const mainNav = document.getElementById('main-nav');&lt;/p&gt;

&lt;p&gt;navBtn.addEventListener('click', () =&amp;gt; {&lt;br&gt;
  const isExpanded = navBtn.getAttribute('aria-expanded') === 'true';&lt;br&gt;
  navBtn.setAttribute('aria-expanded', !isExpanded);&lt;br&gt;
  mainNav.hidden = isExpanded;&lt;/p&gt;

&lt;p&gt;// Update label to reflect current state&lt;br&gt;
  navBtn.setAttribute('aria-label', &lt;br&gt;
    isExpanded ? 'Open navigation menu' : 'Close navigation menu'&lt;br&gt;
  );&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;Three things the fix adds that the original lacked: native keyboard focus, a name that screen readers can announce, and a state (aria-expanded) that tells assistive technology whether the menu is open or closed.&lt;/p&gt;

&lt;p&gt;The SVG gets aria-hidden="true" and focusable="false" because the button's aria-label already provides the accessible name, the icon is decorative in this context.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PATTERN 3 — Form controls that are visually present but keyboard-unreachable&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Heading: The form field keyboard users cannot interact with — even when it looks completely normal&lt;/p&gt;

&lt;p&gt;This pattern is the most damaging from a conversion standpoint, because it appears inside forms — the exact flows where users need to complete a transaction, submit a request, or finish a registration.&lt;br&gt;
The specific case we documented: a date of birth selector in a quote request form. Visually it renders as a date picker. Functionally it's implemented like this:&lt;/p&gt;

&lt;p&gt;html&lt;/p&gt;

&lt;p&gt;Select date of birth&lt;/p&gt;



&lt;p&gt;The &lt;/p&gt; has no tabindex, no role, no keyboard event handlers. Tab skips it. Enter does nothing. The type="hidden" input is intentionally invisible to the browser's accessibility tree.

&lt;p&gt;A keyboard user reaches this step and has no way forward. The form cannot be completed. This fails WCAG 2.1.1 (Keyboard) at the Critical severity level, it's not a degraded experience, it's a complete blocker.&lt;/p&gt;

&lt;p&gt;This specific pattern appears frequently in date pickers, custom dropdowns, color pickers, and any component where a developer uses a hidden input to store the value while a custom UI element handles the visual presentation. The custom UI element almost never has keyboard support.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
The trigger needs to be a real interactive element with keyboard support, an accessible name, and ARIA attributes that communicate its current state:&lt;/p&gt;

&lt;p&gt;html&lt;br&gt;

  id="dob-trigger"&lt;br&gt;
  aria-haspopup="dialog"&lt;br&gt;
  aria-label="Date of birth, no date selected"&lt;br&gt;
  aria-expanded="false"&amp;gt;&lt;br&gt;
  Select date of birth&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;
  type="text" &lt;br&gt;
  id="dob-field"&lt;br&gt;
  name="dob"&lt;br&gt;
  aria-label="Date of birth"&lt;br&gt;
  placeholder="MM/DD/YYYY"&lt;br&gt;
  autocomplete="bday"&amp;gt;&lt;/p&gt;

&lt;p&gt;javas&lt;br&gt;
criptconst dobTrigger = document.getElementById('dob-trigger');&lt;br&gt;
const dobField = document.getElementById('dob-field');&lt;/p&gt;

&lt;p&gt;dobTrigger.addEventListener('keydown', (e) =&amp;gt; {&lt;br&gt;
  if (e.key === 'Enter' || e.key === ' ') {&lt;br&gt;
    e.preventDefault();&lt;br&gt;
    openDatepicker();&lt;br&gt;
  }&lt;br&gt;
});&lt;/p&gt;

&lt;p&gt;function onDateSelected(date) {&lt;br&gt;
  const formatted = formatDate(date); // e.g. "06/15/1990"&lt;br&gt;
  dobField.value = formatted;&lt;/p&gt;

&lt;p&gt;// Update the trigger label to reflect selection&lt;br&gt;
  dobTrigger.setAttribute(&lt;br&gt;
    'aria-label',&lt;br&gt;
    Date of birth, ${formatted} selected. Press Enter to change.&lt;br&gt;
  );&lt;/p&gt;

&lt;p&gt;// Return focus to trigger after selection&lt;br&gt;
  dobTrigger.focus();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;The key principle: whatever value the user selects must be reflected in the accessible name of the trigger, so screen reader users know what they've chosen without having to navigate away from the component.&lt;/p&gt;

&lt;p&gt;If you're using a third-party date picker library, check whether it exposes keyboard navigation and ARIA attributes before integrating it. Most don't by default.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WHY THESE THREE KEEP APPEARING&lt;/strong&gt;&lt;br&gt;
These aren't obscure edge cases. They're the result of three patterns that are extremely common in how front-end development gets prioritized:&lt;/p&gt;

&lt;p&gt;The focus indicator gets removed because the default browser outline "looks bad" and replacing it properly gets deprioritized. The accessible name and keyboard support get skipped because the component works visually and passes a quick manual click-through. The form control gets built with a hidden input because that's the easiest way to decouple the visual presentation from the data layer, and accessibility testing never reaches the keyboard interaction path.&lt;/p&gt;

&lt;p&gt;None of these are malicious decisions. They're prioritization gaps, and they compound: a site with all three patterns effectively locks out every keyboard user from navigating, finding the menu, and completing a form.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WHAT STATIC SCANNERS WON'T CATCH&lt;/strong&gt;&lt;br&gt;
axe and Lighthouse will flag missing alt text and low color contrast reliably. They will not catch any of the three patterns above.&lt;/p&gt;

&lt;p&gt;The outline: none rule sits in CSS, scanners don't simulate keyboard navigation to verify whether focus is visible. The &lt;code&gt;&amp;lt;a&amp;gt;&lt;/code&gt; without href may not trigger a violation depending on how the tool evaluates focusability. The hidden input pattern passes most automated checks because the element is intentionally hidden and the visible trigger has no semantic role to flag.&lt;/p&gt;

&lt;p&gt;Manual keyboard testing, Tab through every interactive element, verify focus is visible, verify every control responds to Enter and Space — is the only reliable way to catch these.&lt;/p&gt;

&lt;p&gt;If you want to run a quick check on a live URL without a full manual audit, A11yDetector navigates tab by tab and surfaces exactly this class of issue: &lt;a href="https://www.a11ysolutions.com/detector/" rel="noopener noreferrer"&gt;a11ysolutions.com/detector&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Three different sites. Three different stacks. The same three failures.&lt;/p&gt;

&lt;p&gt;Keyboard accessibility breaks in predictable ways. The patterns are consistent enough that once you know what to look for, you'll spot them in minutes on almost any site you audit.&lt;/p&gt;

&lt;p&gt;The fixes are equally consistent: use semantic HTML, don't suppress focus styles, and test with a keyboard before shipping.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
      <category>css</category>
      <category>wcag</category>
    </item>
    <item>
      <title>Why your accessibility tree is now your AI strategy</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Wed, 24 Jun 2026 09:52:42 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/why-your-accessibility-tree-is-now-your-ai-strategy-471h</link>
      <guid>https://dev.to/a11ysolutions/why-your-accessibility-tree-is-now-your-ai-strategy-471h</guid>
      <description>&lt;p&gt;Most developers think of accessibility as a checklist. WCAG compliance. Screen reader support. Alt text on images.&lt;br&gt;
That framing is outdated.&lt;/p&gt;

&lt;p&gt;Here's what's actually happening in 2026: AI agents like ChatGPT, Gemini, and Perplexity don't read your website the way a sighted user does. They walk your DOM. They parse your ARIA roles, your heading hierarchy, your semantic HTML.&lt;/p&gt;

&lt;p&gt;Sound familiar? It should. That's exactly what a screen reader does.&lt;br&gt;
The accessibility tree you build for users with disabilities is the same structure an AI agent relies on to navigate, extract information, and complete tasks on a user's behalf.&lt;/p&gt;

&lt;p&gt;95.9% of websites have detectable WCAG failures. (WebAIM, 2026)&lt;br&gt;
That means 95.9% of websites are also partially invisible to AI-driven discovery.&lt;/p&gt;

&lt;p&gt;The fix is the same for both:&lt;/p&gt;

&lt;p&gt;Semantic HTML first&lt;br&gt;
Correct heading hierarchy&lt;br&gt;
Meaningful alt text&lt;br&gt;
Proper ARIA labels&lt;br&gt;
Keyboard-operable interactions&lt;/p&gt;

&lt;p&gt;We explored this in depth with &lt;strong&gt;Zammo.ai&lt;/strong&gt; in a piece we co-authored on why digital accessibility is now also an AI strategy. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.a11ysolutions.com/blog/why-digital-accessibility-is-an-ai-strategy/" rel="noopener noreferrer"&gt;https://www.a11ysolutions.com/blog/why-digital-accessibility-is-an-ai-strategy/&lt;/a&gt;&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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq39hs5in28dkedrsa05r.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.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fq39hs5in28dkedrsa05r.png" alt="They read the same way. Screen readers and AI agents both rely on structure, hierarchy, and semantic code. Co-branded by A11ySolutions and Zammo.ai." width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>ai</category>
      <category>agents</category>
      <category>a11y</category>
    </item>
    <item>
      <title>How I cut accessibility remediation time by 70% without leaving VS Code</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Thu, 18 Jun 2026 14:24:38 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/how-i-cut-accessibility-remediation-time-by-70-without-leaving-vs-code-igi</link>
      <guid>https://dev.to/a11ysolutions/how-i-cut-accessibility-remediation-time-by-70-without-leaving-vs-code-igi</guid>
      <description>&lt;p&gt;&lt;strong&gt;The problem&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every time I found an accessibility issue in a PR review, the same thing happened: tab out to the WCAG docs, figure out the right fix, come back to the code, apply it, re-verify. For every single issue.&lt;/p&gt;

&lt;p&gt;It wasn't hard work. It was repetitive work. And it was eating hours every sprint.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What we built&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A11yResolver is a VS Code extension that brings that entire loop inside the editor.&lt;/p&gt;

&lt;p&gt;It runs as an AI agent. It flags WCAG issues in context, not as static linting, but understanding the component and what it produces. Then it suggests a standards-based fix you can review as a diff and apply with one click.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The two modes&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issues Resolver Fast&lt;/strong&gt; — the everyday one. Missing labels, non-semantic buttons, form field associations, basic keyboard support. Quick iteration, lower cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issues Resolver Expert&lt;/strong&gt; — for the harder stuff. Focus traps, dynamic ARIA states, live regions, complex multi-step flows. More reasoning power for the edge cases.&lt;/p&gt;

&lt;p&gt;Start with Fast. Switch to Expert when it can't fully resolve something.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What surprised me&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It validates fixes through real browser interaction, not just code analysis. It actually simulates keyboard navigation and checks that focus management works correctly. That's the part most tools skip.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Setup&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install from the VS Code Marketplace: &lt;a href="https://marketplace.visualstudio.com/items?itemName=A11YSolutions.a11y-resolver-vscode-chat" rel="noopener noreferrer"&gt;https://marketplace.visualstudio.com/items?itemName=A11YSolutions.a11y-resolver-vscode-chat&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Open the A11yResolver panel from the sidebar&lt;/li&gt;
&lt;li&gt;Add your OpenRouter API key (stored in VS Code secrets, never sent to A11ySolutions)&lt;/li&gt;
&lt;li&gt;Point it at any component&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Your own API key means you pay the token cost directly, no markup, no subscription for the AI part. Free during beta.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Results&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In the projects where we've tracked it: 50–70% less time on repetitive remediation. The gain isn't speed, it's not doing the work twice.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Try it&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;→ &lt;a href="https://marketplace.visualstudio.com/items?itemName=A11YSolutions.a11y-resolver-vscode-chat" rel="noopener noreferrer"&gt;VS Code Marketplace&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://app.trupeer.ai/view/2meqGnCDI/a-11-y-resolver-user-guide" rel="noopener noreferrer"&gt;Full demo&lt;/a&gt;&lt;br&gt;
→ &lt;a href="https://www.a11ysolutions.com/resolver" rel="noopener noreferrer"&gt;Product page&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Questions welcome in the comments.&lt;/p&gt;

</description>
      <category>a11y</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Your accessibility fixes are good. But do you know what they're worth?</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Fri, 29 May 2026 10:43:23 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/your-accessibility-fixes-are-good-but-do-you-know-what-theyre-worth-125k</link>
      <guid>https://dev.to/a11ysolutions/your-accessibility-fixes-are-good-but-do-you-know-what-theyre-worth-125k</guid>
      <description>&lt;p&gt;YI put together a visual breakdown of this concept as a LinkedIn carousel — &lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7463483946497069056" rel="noopener noreferrer"&gt;check it out here&lt;/a&gt; before diving into the full article.our accessibility fixes are good. But do you know what they're worth?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The audit is not the full picture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You've run the audit. Fixed the contrast ratios. Added the missing alt text. Resolved the keyboard trap on that modal that's been broken for six months.&lt;/p&gt;

&lt;p&gt;WCAG compliance is checked. The report is clean.&lt;/p&gt;

&lt;p&gt;And then someone from product or leadership asks:&lt;/p&gt;

&lt;p&gt;"Great, but what did that actually do for the business?"&lt;/p&gt;

&lt;p&gt;Most developers don't have a good answer to that question. Not because the work isn't valuable, it is, but because no one built the bridge between the technical fix and the business outcome.&lt;/p&gt;

&lt;p&gt;This article is that bridge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The drop-offs your analytics will never show you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accessibility failures are invisible to standard tracking. They happen before the click, before the form event fires, before any tracker registers them.&lt;/p&gt;

&lt;p&gt;A broken focus trap on a modal. A form that doesn't announce errors to screen readers. A date picker that keyboard users simply can't complete.&lt;/p&gt;

&lt;p&gt;These aren't just WCAG failures. They're conversion failures.&lt;/p&gt;

&lt;p&gt;The math is straightforward&lt;/p&gt;

&lt;p&gt;What changes when you improve accessibility is the effective conversion rate — because you're removing friction that was silently blocking a portion of your users from completing the flow.&lt;/p&gt;

&lt;p&gt;Industry studies consistently show conversion uplifts in the range of 10–14% after focused accessibility remediation on critical flows. Support ticket volume drops. Abandonment in key steps decreases.&lt;/p&gt;

&lt;p&gt;We built a free ROI calculator that takes exactly those inputs and returns a projected revenue impact based on verified industry data.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.a11ysolutions.com/roi-calculator/" rel="noopener noreferrer"&gt;Calculate the ROI of your accessibility work&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No sign-up. No pitch. Just your number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters beyond the ticket&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're a developer who cares about accessibility, and if you're reading this, you probably do — you already know the work is worth doing.&lt;/p&gt;

&lt;p&gt;But knowing how to communicate its value to a product manager, a CTO, or a leadership team is a different skill. And it's one that determines whether accessibility stays a priority after the first audit, or gets deprioritized when the next quarter's roadmap fills up.&lt;/p&gt;

&lt;p&gt;Run the calculator before your next sprint review. Share the number with your product lead. It's a two minute exercise that can change how accessibility is resourced on your team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The takeaway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accessibility fixes reduce friction. Reduced friction improves conversion. Improved conversion is measurable revenue.&lt;/p&gt;

&lt;p&gt;The chain is direct. Most teams just never close the loop.&lt;/p&gt;

&lt;p&gt;Now you can.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.a11ysolutions.com/roi-calculator/" rel="noopener noreferrer"&gt;a11ysolutions.com/roi-calculator&lt;/a&gt;&lt;/p&gt;

</description>
      <category>a11y</category>
    </item>
    <item>
      <title>3 accessibility failures we find in every fintech onboarding flow.</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Tue, 26 May 2026 09:54:50 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/3-accessibility-failures-we-find-in-every-fintech-onboarding-flow-12k6</link>
      <guid>https://dev.to/a11ysolutions/3-accessibility-failures-we-find-in-every-fintech-onboarding-flow-12k6</guid>
      <description>&lt;p&gt;We audited several fintech onboarding flows this quarter. Different companies, different stacks, different teams.&lt;/p&gt;

&lt;p&gt;Same three issues. Every time.&lt;/p&gt;

&lt;p&gt;None of them appeared in automated scans. All of them showed up in the first 30 minutes of expert review. Here's what they are and how to fix them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue #1 — Email field with no visible label&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The field looks fine visually. There's placeholder text that says "Enter your email." But there's no &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt; element connected to it.&lt;/p&gt;

&lt;p&gt;For a screen reader user, the field is either announced without context or skipped entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&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%2F9yd4y9xgrjjoqmt3j56h.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%2F9yd4y9xgrjjoqmt3j56h.png" alt="HTML code showing a label element connected to an email input field using matching for and id attributes" width="594" height="97"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you can't modify the label structure, use &lt;code&gt;aria-label&lt;/code&gt; as a fallback:&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%2Fxoewkxee2z61wj4wyao0.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%2Fxoewkxee2z61wj4wyao0.png" alt="HTML code showing an email input field using aria-label attribute as an accessible name fallback" width="606" height="76"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to test with NVDA + Chrome:&lt;/strong&gt;&lt;br&gt;
Tab into the field. NVDA should announce "Email address, edit text." If it announces only "edit text" or nothing, you have this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue #2 — Password validation that disappears&lt;/strong&gt;&lt;br&gt;
The error message appears when the user types a weak password, then vanishes after a second. Sighted users catch it. Users with low vision or screen readers miss it entirely.&lt;/p&gt;

&lt;p&gt;The fix is to use &lt;code&gt;aria-live&lt;/code&gt; so assistive technology announces the message when it appears:&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%2Fy0nsfffe7v0a0t8ldfpx.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%2Fy0nsfffe7v0a0t8ldfpx.png" alt="HTML code showing a div element with aria-live set to polite used to announce password validation messages to screen readers" width="528" height="79"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then inject the validation message into that container via JavaScript. The screen reader will announce it automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to test:&lt;/strong&gt;&lt;br&gt;
Trigger the validation error. If NVDA doesn't announce the message out loud, you have this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Issue #3 — Continue button unreachable via Tab on mobile&lt;/strong&gt;&lt;br&gt;
The button exists in the DOM. It looks tappable. But keyboard and switch access users on mobile can't reach it because focus order is broken or the element isn't natively focusable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
Use a native &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt; element instead of a styled &lt;code&gt;&amp;lt;div&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;. Native buttons are focusable and keyboard-operable by default.&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%2Flkpvi88i2jfplga5o3q6.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%2Flkpvi88i2jfplga5o3q6.png" alt="HTML code comparing an inaccessible div element used as a button versus a native button element that is keyboard focusable by default" width="623" height="168"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you must use a custom element, add &lt;code&gt;tabindex="0"&lt;/code&gt; and handle keyboard events explicitly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to test:&lt;/strong&gt;&lt;br&gt;
On mobile, connect a Bluetooth keyboard. Tab through the form. If you can't reach the Continue button, you have this issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Quick checklist before you ship an onboarding flow&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Every input has a visible, connected &lt;code&gt;&amp;lt;label&amp;gt;&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Error messages use &lt;code&gt;aria-live&lt;/code&gt; or &lt;code&gt;role="alert"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;All interactive elements are reachable via Tab&lt;/li&gt;
&lt;li&gt;No action depends exclusively on placeholder text&lt;/li&gt;
&lt;li&gt;The flow is testable with NVDA or VoiceOver in under 10 minutes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;These issues don't show up in automated scans.&lt;/strong&gt;&lt;br&gt;
Automated tools check structure. They don't simulate how a real user navigates with a screen reader, a keyboard, or a switch device. That's what expert audits are for.&lt;/p&gt;

&lt;p&gt;If you want to know whether your onboarding has these issues, start here.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Your accessibility fixes are good. But do you know what they're worth?</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Thu, 21 May 2026 09:04:28 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/your-accessibility-fixes-are-good-but-do-you-know-what-theyre-worth-2igk</link>
      <guid>https://dev.to/a11ysolutions/your-accessibility-fixes-are-good-but-do-you-know-what-theyre-worth-2igk</guid>
      <description>&lt;p&gt;I put together a visual breakdown of this concept as a LinkedIn carousel -&lt;a href="https://www.linkedin.com/feed/update/urn:li:activity:7463121450070212609" rel="noopener noreferrer"&gt;https://www.linkedin.com/feed/update/urn:li:activity:7463121450070212609&lt;/a&gt; before diving into the full article.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The audit is not the full picture&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You've run the audit. Fixed the contrast ratios. Added the missing alt text. Resolved the keyboard trap on that modal that's been broken for six months.&lt;/p&gt;

&lt;p&gt;WCAG compliance is checked. The report is clean.&lt;/p&gt;

&lt;p&gt;And then someone from product or leadership asks:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Great — but what did that actually do for the business&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most developers don't have a good answer to that question. Not because the work isn't valuable, it is, but because no one built the bridge between the technical fix and the business outcome.&lt;/p&gt;

&lt;p&gt;This article is that bridge.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The drop-offs your analytics will never show you&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Here's something worth understanding about accessibility failures: most of them are invisible to standard tracking.&lt;/p&gt;

&lt;p&gt;When a screen reader user hits a form that doesn't announce validation errors, they don't trigger an error event. They just stop. When a keyboard user encounters a focus trap inside a modal they can't escape, there's no rage click, no heatmap signal, no session recording that captures what happened.&lt;/p&gt;

&lt;p&gt;They leave. Quietly. Before your funnel even starts.&lt;/p&gt;

&lt;p&gt;This is the category of lost revenue that never appears in any dashboard, and it's directly caused by inaccessible components.&lt;/p&gt;

&lt;p&gt;A broken &lt;code&gt;aria-live&lt;/code&gt; region. A missing &lt;code&gt;role="alert"&lt;/code&gt;. A date picker built without keyboard support. A checkout button that's visually styled but not semantically a button.&lt;/p&gt;

&lt;p&gt;These aren't edge cases. They're patterns that repeat across almost every production codebase.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility barriers are conversion failures&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The framing matters here.&lt;/p&gt;

&lt;p&gt;When you fix a focus management issue, you're not just passing a WCAG 2.1 success criterion. You're removing a barrier that was preventing a subset of your users from completing a critical task, booking, purchasing, registering, submitting.&lt;/p&gt;

&lt;p&gt;That subset is larger than most teams assume. It includes users with permanent disabilities, but also users on keyboard-only setups, users with temporary injuries, power users who tab through forms, and older users who rely on larger text and higher contrast.&lt;/p&gt;

&lt;p&gt;When that barrier is removed, task completion goes up. And task completion is conversion.&lt;/p&gt;

&lt;p&gt;The technical fix and the business outcome are the same event, most teams just never measure them together.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to calculate what your accessibility work is actually worth&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This is where it gets concrete.&lt;/p&gt;

&lt;p&gt;The variables that determine the revenue impact of accessibility remediation are the same variables your analytics team already tracks:&lt;/p&gt;

&lt;p&gt;Monthly traffic, conversion rate, average order value, and industry sector.&lt;/p&gt;

&lt;p&gt;What changes when you improve accessibility is the effective conversion rate, because you're removing friction that was silently blocking a portion of your users from completing the flow.&lt;/p&gt;

&lt;p&gt;We built a free ROI calculator that takes exactly those inputs and returns a projected revenue impact based on verified industry data, not generic estimates, but numbers calibrated to your traffic, your conversion rate, and your sector.&lt;/p&gt;

&lt;p&gt;👉 Calculate the ROI of your accessibility work -&lt;a href="https://www.a11ysolutions.com/roi-calculator/" rel="noopener noreferrer"&gt;https://www.a11ysolutions.com/roi-calculator/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;No sign-up. No pitch. Just your number.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why this matters beyond the ticket&lt;/strong&gt;&lt;br&gt;
If you're a developer who cares about accessibility, and if you're reading this, you probably do, you already know the work is worth doing.&lt;/p&gt;

&lt;p&gt;But knowing how to communicate its value to a product manager, a CTO, or a leadership team is a different skill. And it's one that determines whether accessibility stays a priority after the first audit, or gets deprioritized when the next quarter's roadmap fills up.&lt;/p&gt;

&lt;p&gt;The ROI calculator doesn't replace your expertise. It gives your work a language that the rest of the organization understands.&lt;/p&gt;

&lt;p&gt;Run it before your next sprint review. Share the number with your product lead. It's a two-minute exercise that can change how accessibility is resourced on your team.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The takeaway&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Accessibility fixes reduce friction. Reduced friction improves conversion. Improved conversion is measurable revenue.&lt;/p&gt;

&lt;p&gt;The chain is direct. Most teams just never close the loop.&lt;/p&gt;

&lt;p&gt;Now you can.&lt;/p&gt;

&lt;p&gt;👉 &lt;a href="https://www.a11ysolutions.com/roi-calculator/" rel="noopener noreferrer"&gt;https://www.a11ysolutions.com/roi-calculator/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>ux</category>
    </item>
    <item>
      <title>Accessible error messages: the patterns that work across JAWS, NVDA and VoiceOver</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Mon, 18 May 2026 11:36:38 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/accessible-error-messages-the-patterns-that-work-across-jaws-nvda-and-voiceover-1b5n</link>
      <guid>https://dev.to/a11ysolutions/accessible-error-messages-the-patterns-that-work-across-jaws-nvda-and-voiceover-1b5n</guid>
      <description>&lt;p&gt;You added &lt;code&gt;aria-live="assertive"&lt;/code&gt;. You set &lt;code&gt;aria-invalid="true"&lt;/code&gt;. You tested in Chrome with a mouse.&lt;/p&gt;

&lt;p&gt;The error message works perfectly.&lt;/p&gt;

&lt;p&gt;Then a JAWS user fills out your form and hears... nothing useful. Or worse,they hear the error, but by the time they navigate back to the field, the message is gone.&lt;/p&gt;

&lt;p&gt;Two real cases from audits that show exactly where this breaks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1: The toast that disappeared before the user could act&lt;/strong&gt;&lt;br&gt;
An e-learning platform displayed validation errors as auto-dismissing toasts with &lt;code&gt;data-delay="8000"&lt;/code&gt;. Eight seconds sounds reasonable until you map what a screen reader user actually needs to do: hear the announcement, understand the error, navigate back to the field, correct it, re-submit. On a complex form, that's not enough time, and the message was gone before they could act.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;WCAG failure: SC 2.2.1 — Timing Adjustable.&lt;/strong&gt; Any time limit must be removable or adjustable. An 8-second toast carrying critical error information fails outright.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fix:&lt;/strong&gt; don't use auto-dismissing toasts for errors. Toasts work for redundant, low-stakes notifications. Not for information the user needs to act on. Display errors inline, adjacent to the field, and keep them visible until the user corrects the input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2: The error that vanished when focus left the field&lt;/strong&gt;&lt;br&gt;
A form showed the error while the field was focused, but an &lt;code&gt;onblur&lt;/code&gt; listener hid the container the moment the user tabbed away. The screen reader announced only "invalid entry." No explanation, no guidance.&lt;/p&gt;

&lt;p&gt;Two bugs in one component. First, the message disappeared on blur, so any user who tabbed to the next field and back found it gone. Second, there was no &lt;code&gt;aria-describedby&lt;/code&gt; linking the error text to the input,so even when the message was visible, JAWS and NVDA had no reason to read it on focus.&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%2Fxgu61a8kvo8xmou00817.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%2Fxgu61a8kvo8xmou00817.png" alt="Code comparison showing two HTML implementations of an inline error message. The " span="" id="email-error" width="674" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;With &lt;code&gt;aria-describedby&lt;/code&gt; in place, JAWS, NVDA and VoiceOver all read the error automatically when the field receives focus. Remove the blur handler. Errors should persist until the user successfully corrects the field.&lt;/p&gt;

&lt;p&gt;Both bugs come down to the same root cause: errors that aren't persistent and aren't programmatically connected to their field. Fix those two things and you cover the vast majority of screen reader failure modes on form validation.&lt;/p&gt;

&lt;p&gt;What patterns are you using for error handling? Curious if anyone's hit edge cases with VoiceOver + Safari on iOS, that combination still has quirks worth discussing.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
      <category>html</category>
    </item>
    <item>
      <title>Focus indicators that fail WCAG 1.4.11: real cases and exact fixes</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Wed, 13 May 2026 08:52:26 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/focus-indicators-that-fail-wcag-1411-real-cases-and-exact-fixes-4aeo</link>
      <guid>https://dev.to/a11ysolutions/focus-indicators-that-fail-wcag-1411-real-cases-and-exact-fixes-4aeo</guid>
      <description>&lt;p&gt;&lt;strong&gt;What is a focus indicator — and why does WCAG regulate it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When a user navigates a website using a keyboard, they need to know where they are on the page at all times. The focus indicator is the visual signal that answers that question: the outline, highlight, or state change that appears on the element currently receiving keyboard focus.&lt;/p&gt;

&lt;p&gt;WCAG Success Criterion 1.4.11 (Non-text Contrast) requires that the visual presentation of UI components, including focus and hover indicators, has a contrast ratio of at least 3:1 against adjacent colors.&lt;/p&gt;

&lt;p&gt;Without a sufficient focus indicator:&lt;/p&gt;

&lt;p&gt;Keyboard-only users lose their place on the page.&lt;br&gt;
Users with low vision cannot perceive the current focus state.&lt;br&gt;
The product fails a Level AA audit, the standard required by the EAA, ADA, and EN 301 549.&lt;/p&gt;

&lt;p&gt;Below are three real cases from accessibility audits, extracted from a structured issue bank. No simulated data. No approximations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1&lt;/strong&gt; — Login page: Dropdown focused/hovered option&lt;br&gt;
&lt;strong&gt;Component:&lt;/strong&gt; "Tipo de documento" dropdown — focused and hovered option state&lt;br&gt;
&lt;strong&gt;Audit type:&lt;/strong&gt; Color Contrast · Priority: High&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was found:&lt;/strong&gt;&lt;br&gt;
When the dropdown expanded and the user hovered or focused an option, the selected state was communicated only through a light grey background. There was no outline or other indicator with sufficient contrast.&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%2Fkbzad7pbt0wh4qs1hfy7.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%2Fkbzad7pbt0wh4qs1hfy7.png" alt="Table showing a WCAG 1.4.11 contrast failure where the focused option background color (#F1F4F4) is compared against a white page background (#FFFFFF). The measured contrast ratio is 1.1:1, below the required minimum of 3:1." width="798" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The CSS driving the problem:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;.css-1kwd9xn-option {&lt;br&gt;
  background-color: rgb(241, 244, 244); /* #F1F4F4 */&lt;br&gt;
  color: rgb(0, 43, 69);&lt;br&gt;
  font-size: 14px;&lt;br&gt;
  font-weight: normal;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;A ratio of 1.1:1 means the focused state is virtually indistinguishable from the default state. For a user with low vision navigating with a keyboard, the dropdown is effectively unusable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
Replace the near-white background with a grey that achieves the required 3:1 threshold against the white page background.&lt;br&gt;
css/* Before &lt;em&gt;/&lt;br&gt;
.css-1kwd9xn-option {&lt;br&gt;
  background-color: rgb(241, 244, 244); /&lt;/em&gt; ratio 1.1:1 — FAIL */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;/* After &lt;em&gt;/&lt;br&gt;
.css-1kwd9xn-option:hover,&lt;br&gt;
.css-1kwd9xn-option:focus {&lt;br&gt;
  background-color: #939393; /&lt;/em&gt; ratio 3.0:1 against #FFFFFF — PASS */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2&lt;/strong&gt; — Login page: Password digit field borders&lt;br&gt;
&lt;strong&gt;Component:&lt;/strong&gt; Input field boundaries — digit fields for password entry&lt;br&gt;
&lt;strong&gt;Audit type:&lt;/strong&gt; Color Contrast · Priority: Medium&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was found:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The password entry screen used a series of individual digit input fields. Each field had only a bottom border as its visible boundary — the indicator that communicates "this is an input". That border failed the 3:1 contrast requirement against the white background.&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%2F0zvj909uqipq8g05l73b.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%2F0zvj909uqipq8g05l73b.png" alt="Table showing a WCAG 1.4.11 non-text contrast failure for an input bottom border color (#CCD5DA) against a white background (#FFFFFF). The measured contrast ratio is 1.48:1, below the required minimum of 3:1." width="799" height="236"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;WCAG 1.4.11 applies not only to focus rings but to any visual indicator that communicates the presence or boundary of an interactive component. A field border that a user cannot see means they cannot locate the input.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
Use a darker grey for the border that maintains the visual style while meeting the threshold.&lt;/p&gt;

&lt;p&gt;css/* Before &lt;em&gt;/&lt;br&gt;
.password-digit-field {&lt;br&gt;
  border-bottom: 1px solid #CCD5DA; /&lt;/em&gt; ratio 1.48:1 — FAIL */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;/* After &lt;em&gt;/&lt;br&gt;
.password-digit-field {&lt;br&gt;
  border-bottom: 1px solid #8094A3; /&lt;/em&gt; ratio 3.14:1 — PASS */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 3&lt;/strong&gt; — Account page: Radio button borders&lt;br&gt;
&lt;strong&gt;Component:&lt;/strong&gt; Radio button visual boundaries — payment method selection&lt;br&gt;
&lt;strong&gt;Audit type:&lt;/strong&gt; Color Contrast · Priority: Low&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What was found:&lt;/strong&gt;&lt;br&gt;
A payment method selection screen presented a group of radio buttons for choosing between credit cards. The unchecked radio buttons used a light grey border to indicate their boundary. That border failed 3:1 against the white background.&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%2F37q8ure9e1dw2w59yong.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%2F37q8ure9e1dw2w59yong.png" alt="Table showing a WCAG 1.4.11 non-text contrast failure for a radio button border color (#C2CFD6) against a white background (#FFFFFF). The measured contrast ratio is 1.59:1, below the required minimum of 3:1." width="799" height="238"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When radio button borders are invisible, users with low vision cannot detect that a selectable option is present. This is a form usability failure, not just an aesthetic one: invisible controls block task completion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The fix:&lt;/strong&gt;&lt;br&gt;
css/* Before &lt;em&gt;/&lt;br&gt;
.sc-radio-field-label:before {&lt;br&gt;
  border: 0.0625rem solid #C2CFD6; /&lt;/em&gt; ratio 1.59:1 — FAIL */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;/* After &lt;em&gt;/&lt;br&gt;
.sc-radio-field-label:before {&lt;br&gt;
  border: 0.0625rem solid #949494; /&lt;/em&gt; ratio 3.03:1 — PASS */&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What these three cases have in common&lt;/strong&gt;&lt;br&gt;
All three failures share the same root cause: grey UI elements on white backgrounds, where the grey is not dark enough to reach 3:1.&lt;/p&gt;

&lt;p&gt;This pattern is extremely common in design systems that prioritize subtle, minimal aesthetics. The visual result feels clean. The accessibility result is that a significant portion of users cannot perceive the interface.&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%2Fl8tbkpvo8jkfo6jx8vg7.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%2Fl8tbkpvo8jkfo6jx8vg7.png" alt="Table comparing failing and corrected WCAG 1.4.11 non-text contrast ratios for three UI components: dropdown focused state improved from 1.1:1 to 3.0:1 using color #939393, password field border improved from 1.48:1 to 3.14:1 using color #8094A3, and radio button border improved from 1.59:1 to 3.03:1 using color #949494." width="799" height="195"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;None of these fixes required redesigning the component. Each required changing one CSS color value.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Focus indicators failing WCAG 1.4.11: real cases and exact fixes</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Tue, 12 May 2026 11:48:12 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/focus-indicators-failing-wcag-1411-real-cases-and-exact-fixes-13hm</link>
      <guid>https://dev.to/a11ysolutions/focus-indicators-failing-wcag-1411-real-cases-and-exact-fixes-13hm</guid>
      <description>&lt;p&gt;Focus indicators failing WCAG 1.4.11: real cases and exact fixes&lt;br&gt;
What is a focus indicator?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A focus indicator&lt;/strong&gt; is the visual signal that shows keyboard users which interactive element is currently focused.&lt;/p&gt;

&lt;p&gt;WCAG 2.1 SC 1.4.11 (Non-text Contrast) regulates focus indicators because users navigating with a keyboard must clearly perceive where focus is located.&lt;/p&gt;

&lt;p&gt;The minimum required contrast ratio for visible focus indicators is 3:1 against adjacent colors.&lt;/p&gt;

&lt;p&gt;Why static accessibility tools often miss these issues&lt;/p&gt;

&lt;p&gt;Most static accessibility scanners cannot reliably detect focus indicator failures because the :focus or :focus-visible state only exists during actual keyboard interaction.&lt;/p&gt;

&lt;p&gt;To properly validate focus indicators, manual testing with the keyboard is required.&lt;/p&gt;

&lt;p&gt;Usually:&lt;/p&gt;

&lt;p&gt;Tab&lt;br&gt;
Shift + Tab&lt;br&gt;
Browser DevTools&lt;br&gt;
Contrast analyzers&lt;br&gt;
Real accessibility audit cases&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 1 — Tourism company&lt;/strong&gt;&lt;br&gt;
The primary search button had a focus indicator with a contrast ratio below 3:1.&lt;/p&gt;

&lt;p&gt;Problem&lt;/p&gt;

&lt;p&gt;Keyboard users could technically navigate to the button, but the visible focus state was too subtle to perceive clearly.&lt;/p&gt;

&lt;p&gt;WCAG failure&lt;br&gt;
SC 1.4.11 — Non-text Contrast&lt;br&gt;
Fix&lt;/p&gt;

&lt;p&gt;Use a high-contrast outline with :focus-visible.&lt;/p&gt;

&lt;p&gt;:focus-visible {&lt;br&gt;
  outline: 2px solid #FFFFFF;&lt;br&gt;
  outline-offset: 2px;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 2 — Educational platform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The “Login” button changed from #02959F to #027279 when focused.&lt;/p&gt;

&lt;p&gt;Problem&lt;/p&gt;

&lt;p&gt;Contrast between both visual states was only 1.57:1.&lt;/p&gt;

&lt;p&gt;The component relied exclusively on color to communicate focus.&lt;/p&gt;

&lt;p&gt;WCAG failures&lt;br&gt;
SC 1.4.11 — Non-text Contrast&lt;br&gt;
SC 1.4.1 — Use of Color&lt;br&gt;
Fix&lt;/p&gt;

&lt;p&gt;Add a visible outline independent of color changes.&lt;/p&gt;

&lt;p&gt;:focus-visible {&lt;br&gt;
  outline: 2px solid #FFFFFF;&lt;br&gt;
  outline-offset: 2px;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Case 3 — Same platform&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The “Remember me” checkbox used a black focus indicator (#212529) over a dark background (#1D191C).&lt;/p&gt;

&lt;p&gt;Problem&lt;/p&gt;

&lt;p&gt;Contrast ratio:&lt;/p&gt;

&lt;p&gt;1.12:1&lt;/p&gt;

&lt;p&gt;The focus state became nearly invisible.&lt;/p&gt;

&lt;p&gt;Fix&lt;/p&gt;

&lt;p&gt;Replace the focus indicator with:&lt;/p&gt;

&lt;p&gt;outline: 2px solid #0297A2;&lt;br&gt;
Results&lt;br&gt;
4.92:1 against background&lt;br&gt;
3.79:1 against adjacent colors&lt;/p&gt;

&lt;p&gt;WCAG compliant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How to test focus indicators properly&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Recommended setup:&lt;/p&gt;

&lt;p&gt;Chrome or Firefox&lt;br&gt;
Keyboard navigation only&lt;br&gt;
Colour Contrast Analyser (CCA)&lt;br&gt;
Optional: NVDA or VoiceOver&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Testing steps:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Navigate using only Tab&lt;br&gt;
Verify focus is always visible&lt;br&gt;
Measure contrast of the focus indicator&lt;br&gt;
Validate zoom and dark mode scenarios&lt;br&gt;
Quick production checklist&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Before release, ask:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Can focus be identified immediately?&lt;br&gt;
Does the indicator reach at least 3:1 contrast?&lt;br&gt;
Does the state rely only on color changes?&lt;br&gt;
Is focus still visible in dark mode?&lt;br&gt;
Is it visible at 200% zoom?&lt;/p&gt;

&lt;p&gt;Focus indicators are one of the most commonly overlooked accessibility failures in production systems, especially because many automated tools cannot fully detect them.&lt;/p&gt;

&lt;p&gt;And yet, for keyboard users, they are critical navigation cues.&lt;/p&gt;

&lt;h1&gt;
  
  
  css #accessibility #wcag #webdev #a11y #focusvisible
&lt;/h1&gt;

</description>
      <category>webdev</category>
      <category>css</category>
      <category>a11y</category>
    </item>
    <item>
      <title>Keyboard traps: what they are, how to reproduce them, and how to fix them</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Mon, 11 May 2026 08:01:00 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/keyboard-traps-what-they-are-how-to-reproduce-them-and-how-to-fix-them-157m</link>
      <guid>https://dev.to/a11ysolutions/keyboard-traps-what-they-are-how-to-reproduce-them-and-how-to-fix-them-157m</guid>
      <description>&lt;p&gt;Definition of a keyboard trap according to WCAG 2.1 SC 2.1.2:&lt;/p&gt;

&lt;p&gt;“If keyboard focus can be moved to a component using a keyboard interface, then focus can be moved away from that component using only a keyboard interface.”&lt;/p&gt;

&lt;p&gt;Why can’t static accessibility tools detect it?&lt;/p&gt;

&lt;p&gt;Because detecting a keyboard trap requires actual keyboard navigation — typically using the Tab key.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Real case&lt;/strong&gt; (educational platform):&lt;/p&gt;

&lt;p&gt;The login form contained a keyboard trap. When users activated the “Login” button with empty required fields, keyboard focus was completely lost. Keyboard only users could no longer identify where to continue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problematic HTML&lt;/strong&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;input type="submit" name="commit" value="Entrar" class="btn btn-xchool btn-block mt-4" data-disable-with="Enviando..."&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Solution:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Programmatically move focus to the error message’s “Close” button using &lt;code&gt;focus()&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Tested with Chrome + NVDA.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>html</category>
      <category>a11y</category>
    </item>
    <item>
      <title>5 ARIA mistakes that make accessibility worse, not better</title>
      <dc:creator>a11ySolutions</dc:creator>
      <pubDate>Wed, 06 May 2026 08:34:27 +0000</pubDate>
      <link>https://dev.to/a11ysolutions/5-aria-mistakes-that-make-accessibility-worse-not-better-2pmp</link>
      <guid>https://dev.to/a11ysolutions/5-aria-mistakes-that-make-accessibility-worse-not-better-2pmp</guid>
      <description>&lt;p&gt;There's a rule in accessibility that doesn't get enough attention:&lt;/p&gt;

&lt;p&gt;No ARIA is better than bad ARIA.&lt;/p&gt;

&lt;p&gt;Adding ARIA attributes without understanding them doesn't help assistive tech, it actively misleads it. Here are the mistakes I find most often in real audits:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. role="button" on a div — without keyboard support&lt;/strong&gt;&lt;br&gt;
If you give something a button role, screen readers announce it as a button.&lt;br&gt;
Users expect to activate it with Space or Enter.&lt;br&gt;
If your div only handles onClick, keyboard users get announced a button they can't press. Use &lt;code&gt;&amp;lt;button&amp;gt;&lt;/code&gt;. That's what it's there for.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. aria-label that duplicates visible text — badly&lt;/strong&gt;&lt;br&gt;
&lt;code&gt;&amp;lt;button aria-label="Click here to submit the form"&amp;gt;Submit&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;br&gt;
Screen readers read the aria-label, ignoring "Submit". Now your button is "Click here to submit the form", verbose, inconsistent, and confusing in a list of controls.&lt;br&gt;
If the visible label is accurate, you don't need aria-label.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. aria-hidden="true" on focusable elements&lt;/strong&gt;&lt;br&gt;
Hiding something from the accessibility tree while leaving it focusable creates a ghost, keyboard users can tab to it, but screen readers announce nothing. That's worse than not hiding it at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. aria-live on everything&lt;/strong&gt;&lt;br&gt;
aria-live="assertive" interrupts whatever the screen reader is doing to announce the update. Useful for critical alerts. Catastrophic for &lt;br&gt;
status messages, loading indicators, or anything non-urgent.&lt;br&gt;
Most of the time, aria-live="polite" is what you want, or nothing at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Decorative icons without aria-hidden&lt;/strong&gt;&lt;br&gt;
An icon inside a button with no aria-hidden forces screen readers to &lt;br&gt;
announce the SVG path or file name alongside the button label.&lt;br&gt;
&lt;code&gt;&amp;lt;svg aria-hidden="true"&amp;gt;&lt;/code&gt; is two words. Use them.&lt;/p&gt;

&lt;p&gt;No ARIA is better than bad ARIA.&lt;br&gt;
Before reaching for it, ask if a native HTML element solves it first.&lt;/p&gt;

&lt;p&gt;What ARIA mistakes do you see most in code reviews?&lt;/p&gt;

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