A team we worked with got back an accessibility audit with a page of findings. Missing labels, a few contrast issues, some keyboard traps. Normal stuff. So they did what a lot of teams do: they had an engineer spend a sprint sprinkling role and aria-* attributes across the app, on the theory that more ARIA equals more accessible.
The follow up audit came back worse.
Not because the original issues were still there. They were mostly fixed. The new problems were the ARIA attributes themselves. Several of them were actively lying to screen readers and other assistive technology about what was actually on the page, turning readable buttons into confusing black boxes and hiding real content from the very users the audit was supposed to help.
The Stat: The first rule of ARIA use, published in the W3C's own ARIA Authoring Practices Guide, is: if a native HTML element already has the semantics you need, use it instead of repurposing an element and adding a role. (Source: W3C WAI ARIA Authoring Practices Guide)
Here is that rule made visible, with the four patterns that break it most often in real codebases.
The catalog: four ways teams break the first rule
We already wrote about why the first rule of ARIA exists and why it gets ignored anyway. This piece is the companion to that one. Instead of the philosophy, here is the field guide: the exact patterns that show up in real pull requests, why each one is worse than doing nothing, and the one line fix.
1. The div with role="button" that forgot how to be a button
This is the classic. Someone needs a clickable element that does not look like a default browser button, so they reach for a div, add role="button", wire up an onClick handler, and ship it.
To a sighted mouse user, it works fine. To a screen reader user, it announces as a button. But it is not a button. It has no built in keyboard support, so pressing Tab may never land on it, and pressing Enter or Space does nothing unless a developer manually re-implements keyboard handling that a real <button> gives you for free. The role attribute made a promise that the rest of the markup never kept.
The fix is almost always to just use <button>. You can restyle a button element into anything you want with CSS. What you cannot do with CSS is give a div a keyboard.
2. role="presentation" hiding real, meaningful content
role="presentation" (and its cousin role="none") tells assistive technology "ignore this element's semantics, it's purely decorative." That is genuinely useful for a wrapper div that exists only for layout.
It is genuinely harmful when it lands on something that carries actual information: a price, a stock count, a status badge, a table used to present real tabular data rather than for layout. We have seen this happen when a component library's default styling gets stripped down for a redesign, and whoever did the cleanup left the role="presentation" that used to suppress a decorative icon, except it now sits on the element holding the number a customer needs to see. Screen reader users skip right past it. The content is on the screen and invisible to assistive technology at the same time, which is a strange and specific kind of broken.
The fix is to ask, every time you see role="presentation" in a diff: does this element contain anything a user needs to know? If yes, the role comes off.
3. Redundant roles on native elements that already have one
<nav role="navigation">. <button role="button">. <input type="checkbox" role="checkbox">. Each of these roles is already implicit in the element itself. Adding it back explicitly does not add clarity, it adds a second source of truth that can drift out of sync with the element over time, and it adds nothing for the user, because the browser was already exposing the correct role.
This one is rarely dangerous on its own. It is a smell. It usually means whoever wrote the line did not know the role was automatic, which is exactly the mindset that produces the more serious mistakes on this list. The fix is simply to delete it.
4. aria-hidden left on a focusable element
This is the one that causes the strangest bug reports. A modal closes, a menu collapses, a tooltip dismisses, and the developer sets aria-hidden="true" on the container to hide it from assistive technology while it animates out or stays in the DOM unused. Reasonable so far.
The trap: if that container still holds a link, button, or input that keeps its default tabindex, a keyboard or screen reader user can still Tab into it. Now they are focused on an element the accessibility tree says does not exist. Some screen readers announce nothing. Some behave unpredictably. Either way, the user is stuck inside a hole in the page.
The fix is to remove aria-hidden when the content becomes interactive again, or to set tabindex="-1" (or use the inert attribute) on everything inside the hidden container so focus cannot land there in the first place. We covered a close cousin of this problem, icon only controls that look interactive but skip real semantics entirely, in our hamburger menu confession piece, which is worth reading alongside this one.
A two minute checklist before you ship
None of these four patterns require a rewrite to fix. They require a second pass over the diff, asking a short list of questions before the pull request merges.
- Is there a native element that already does this? A
button,a,select,input,nav,table, ordialogelement comes with keyboard support, focus handling, and a role built in. Reach for it before reaching for adivplus a role. - Does this role match what the element actually does? If you write
role="button"on anything, that element now has to supportTab,Enter, andSpaceexactly like a real button does. If it does not yet, the role is a promise you have not kept. - Does role="presentation" or role="none" sit on anything a user needs to read? If the element carries a price, a count, a status, or any other piece of real information, the role should come off.
- When something gets hidden, does focus get hidden with it? Any time
aria-hidden="true"lands on a container, check whether links, buttons, or inputs inside it can still be tabbed to. If they can, either remove the attribute when the content is interactive again or block focus withtabindex="-1"orinert. - Is the role just restating what the element already announces? A redundant role like
role="navigation"on anavelement is not urgent, but it is a sign the same author may be adding roles out of habit rather than need. Worth a quick look at their other changes.
Run through those five questions on any component that touches ARIA, and most of the damage in this catalog never ships in the first place.
The rule that ties all four together
Every one of these four patterns comes from the same root cause: treating ARIA as decoration you add for credit, instead of a contract you have to keep. Per the W3C's own ARIA Authoring Practices Guide read me first, ARIA only changes what assistive technology is told about an element. It changes nothing about keyboard behavior, focus order, or what actually renders. If you add a role, you have promised the behavior that role implies, and now you have to build it. If you do not need to make that promise, the W3C's guidance on using ARIA is blunt about it: no ARIA is better than bad ARIA.
Before your next audit turns up the same surprise ours did, it is worth running your own components against this catalog. Our free tools can help you spot exactly where a role, an aria-hidden, or a stray role="presentation" is quietly working against you instead of for you.
If you want a second set of eyes on a specific component or a full audit before it becomes a support ticket, reach out to a real person on our team at experts@wcag.world, or start with our free tools to see what's already hiding in your markup.
