A while in the past, I shipped a part that felt accessible by each measure I might check. Keyboard navigation labored. ARIA roles had been accurately utilized. Automated audits handed with out a single criticism. And but, a display screen reader consumer couldn’t work out the way to set off it. Once I examined it myself with keyboard-only navigation and NVDA, I noticed the identical factor: the interplay merely didn’t behave the way in which I anticipated.
Nothing on the guidelines flagged an error. Technically, all the things was “proper.” However in observe, the part wasn’t predictable. Right here’s a simplified model of the part that brought about the difficulty:
As you may see within the demo, the markup is in no way difficult:
And the repair was a lot simpler than anticipated. I needed to delete the ARIA function attribute that I had added with the perfect intentions.
The markup is even simpler than earlier than:
That have modified how I take into consideration accessibility. The largest lesson was this: Semantic HTML does much more accessibility work than we normally give it credit score for already — and ARIA is easy to abuse once we use it each as a shortcut and as a complement.
Many people already know the primary rule of ARIA: don’t use it. Effectively, use it. However not if the accessible advantages and performance you want are already baked in, which it was in my case earlier than including the function attribute.
Let me define precisely what occurred, step-by-step, as a result of I feel the my error is definitely a fairly frequent observe. There are a lot of articles on the market that say precisely what I’m saying right here, however I feel it usually helps to internalize it by listening to it by way of a real-life expertise.
Word: This text was examined utilizing keyboard navigation and a display screen reader (NVDA) to watch actual interplay conduct throughout native and ARIA-modified components.
1: Begin with the only doable markup
Once more, that is merely a minimal web page with a single native and no ARIA. And by default, it permits keyboard focus and demonstrates the performance of utilizing Tab, Enter, and House out of the field. Geoff just lately made this case when explaining the accessibility advantages of semantic HTML components.
If the interplay triggers an motion, then that aspect is a button. And on this case, the is designed to run a script that saves modifications to a consumer profile:
That single line provides us a shocking quantity at no cost:
- Keyboard activation with the
EnterandHousekeys - Appropriate focus conduct
- A task that assistive know-how already understands
- Constant bulletins throughout display screen readers
At this level, there’s no ARIA — and that’s intentional. However I did have an present class for styling buttons in my CSS, so I added that:
2: Observe the native conduct earlier than including something
With simply the native aspect in place, I examined three issues:
- Keyboard solely (Tab, Enter, House)
- A display screen reader (listening to how the management is introduced)
- Focus order inside the web page
All the things behaved predictably. The browser was doing precisely what customers anticipate. This step issues as a result of it establishes a baseline. If one thing breaks later, you understand it wasn’t HTML that brought about it. Actually, we will see that all the things is in good working order by inspecting the aspect in DevTool’s Accessibility panel.

3: Add properly‑intentioned ARIA
The issue crept in once I tried to make the button behave like a hyperlink:
I did this for styling and routing causes. This button wanted to be styled a bit in a different way than the default .cta class and I figured I might use the ARIA attribute moderately than utilizing a modifier class. You can begin to see how I let the styling dictate and affect the performance. A remains to be the proper aspect for this goal, however I wished it to appear to be a hyperlink due to the design necessities. Would possibly as properly give that aspect a hyperlink function then, proper?
On the floor, nothing appeared damaged. Automated instruments stayed quiet. However in actual use, the cracks confirmed shortly:
- House now not activated the management reliably.
- Display readers introduced conflicting roles.
- Keyboard customers encountered conduct that didn’t absolutely match both a button or a hyperlink.
ARIA didn’t add readability right here; it launched ambiguity. However I had already “examined” my work and nothing was screaming at me that I’d conflated the aspect’s function with one other sort of aspect. Once more, all it takes is a fast have a look at DevTools.

4: Again to semantics
The repair wasn’t intelligent. It was subtractive. I reverted my kinds, used a category for styling, and went again to the semantic markup previous to altering the accessible function:
I do know it sounds simple: if it’s an motion, use a . If it takes you someplace, use a hyperlink (). However, in observe, we’re making selections with each key we sort and it’s simply as simple to conflate actions with locations. On this case, I completely used the proper aspect! My mistake was pondering that ARIA was an applicable styling hook for my CSS.
As soon as the proper aspect was in place — absent of ARIA — the problems disappeared. As a substitute, I might outline a brand new classname and, you guessed it, use preserve kinds with kinds.
Identical to that, I used to be in a position to fashion the aspect how I wanted and the consumer who report the difficulty was in a position to verify that all the things labored as anticipated. It was an inadvertent mistake born of a fundamental misunderstanding about ARIA’s place within the stack.
Why this retains occurring
ARIA attributes are used to outline the character of one thing however they don’t redefine the behavioral default of the native components. Once we override semantics, we quietly take accountability for:
- keyboard interactions,
- focus administration,
- anticipated bulletins, and
- platform‑particular quirks.
That’s a big floor space to take care of, and it’s why small ARIA modifications can have outsized and unpredictable results.
A rule I now observe
Right here’s the workflow that has saved me essentially the most time and bugs:
- Use native HTML to precise intent.
- Check with keyboard and a display screen reader.
- Add ARIA solely to speak lacking state, to not redefine roles.
If ARIA feels prefer it’s doing heavy lifting, it’s normally an indication the markup is combating the browser.
The place ARIA does belong
One instance could be a easy disclosure widget utilizing a local plus aria-expanded to speak state — exhibiting ARIA used to add state, not exchange semantics.
This demo makes use of a local with aria-expanded, which is toggled with a sprinkle of JavaScript:
const button = doc.getElementById("toggle");
const panel = doc.getElementById("panel");
button.addEventListener("click on", () => {
const expanded = button.getAttribute("aria-expanded") === "true";
button.setAttribute("aria-expanded", !expanded);
panel.hidden = expanded;
});
The accessible state (true/false) is communicated accurately with out changing the button’s semantics.
Now, I do know that ARIA is important when:
- speaking expanded or collapsed state,
- asserting dynamic updates,
- constructing actually customized widgets, and
- exposing relationships HTML can’t specific.
Used this fashion, ARIA enhances semantic HTML as an alternative of competing with it.
Let the platform be just right for you
The largest accessibility enchancment I’ve made wasn’t studying about extra attributes — it was trusting those browsers already perceive. Semantic HTML will not be the baseline you progress previous. It’s the inspiration that all the things else depends upon.
And that’s what I actually hope you’re taking away from my expertise. All of us make errors. It’s a part of the job, sadly. However what good are they if we will’t study from them, even when it takes a tough lesson.









