ARIA · Development · WCAG 2.1

ARIA: When It Helps, When It Hurts, and the First Rule Everyone Ignores

  • ARIA
  • Development
  • WCAG 2.1

The Fix That Made Things Worse

An audit comes back with a finding: several interactive elements on the site have no programmatically determinable role. A developer, working through the punch list, finds the offending elements — a handful of <div> tags styled to look like buttons, wired up with onclick handlers — and adds role="button" to each one. Finding closed. Ticket resolved. Deploy shipped.

A screen reader user visits the page a week later. Tab lands on one of the "fixed" elements, and the screen reader dutifully announces "button." So far, so good. Then the user presses Enter, the way they've pressed Enter on every button on every website for the last twenty years.

Nothing happens.

They try Space. Nothing. They try Tab again, wondering if focus even landed where the announcement said it did. From their side, this is worse than before the fix. Before, the element at least gave no false signal — it was silently wrong. Now it actively claims to be a button, invites a keyboard interaction that any button should support, and then fails to deliver. The audit finding technically closed. The actual experience got more confusing, not less.

This happens constantly, and it happens because of a misunderstanding about what ARIA actually does.

What ARIA Actually Does — and What It Doesn't

ARIA stands for Accessible Rich Internet Applications. It's a set of attributes — roles, states, and properties — that you add to HTML so that assistive technology can understand custom widgets that plain HTML wasn't built to describe: a tab panel, a combobox with autocomplete, a live status region that updates without a page reload.

Here's the part that trips people up: ARIA only changes what gets announced to assistive technology. It does not add keyboard behavior. It does not manage focus. It does not add any visual styling. It is purely a communication layer that tells screen readers and other assistive tools "this thing is a button" or "this region just updated" — nothing more.

Put role="button" on a <div>, and a screen reader will announce "button." But the <div> still won't respond to Enter or Space unless you write the JavaScript to make it. It still won't have a visible focus indicator unless you style one. It still won't be reachable by Tab unless you add tabindex="0". ARIA changed the label. Nothing else changed on its own.

That's the trap in the story above. The developer fixed the announcement. The element now sounds operable. It isn't. That gap — sounds right, behaves wrong — is arguably worse than a plain unlabeled <div>, because it actively misleads the user into an interaction that fails.

The First Rule of ARIA Use

The W3C's own ARIA Authoring Practices state this directly, and it's worth memorizing word for word:

No ARIA is better than bad ARIA.

This isn't a hedge or a soft suggestion. It's the governing principle behind every other ARIA guideline. A native HTML element like <button>, <a href="...">, or <input> already comes with the correct role, full keyboard behavior, and proper focus handling built in — for free, with zero JavaScript. The browser has been getting this right for decades.

ARIA exists to fill gaps HTML can't fill on its own — not to replace what HTML already does correctly. Reach for it only when you're building something native HTML genuinely cannot express: a custom combobox with live filtering, a tab panel, a modal dialog with a managed focus trap, a status region that needs to announce a change without moving focus.

Everything else — every button, every link, every form field — should just be the actual HTML element. Not a styled <div> with a role bolted on. The real thing.

4.1.2: The Success Criterion ARIA Answers To

4.1.2 Name, Role, Value is a Level A success criterion, and it's the one most directly concerned with whether your ARIA is doing its job. It requires that every UI component have:

  • A programmatically determinable name (what is this thing called?)
  • A programmatically determinable role (what kind of thing is it — a button, a checkbox, a link?)
  • Where applicable, a programmatically determinable state or value that assistive technology can read, and that can be programmatically set by the user for interactive elements

That last clause matters. It's not enough for a screen reader to announce that a checkbox exists and is currently unchecked. The user has to be able to actually change that state using their input method. A visually-styled checkbox built from a <div> with role="checkbox" and aria-checked="false" passes the "announce" half of 4.1.2 and fails the "can be set" half if nobody wired up a click or keyboard handler to toggle it. Half an ARIA widget is a 4.1.2 failure with better PR.

Five Ways ARIA Goes Wrong in the Real World

These aren't hypotheticals — they're patterns that show up in audit after audit.

1. Redundant roles on native elements. role="button" on an actual <button> element. This is harmless — the button already has that role — but it's dead weight in the markup, a sign nobody double-checked before adding it.

2. Mismatched aria-label and visible text. An aria-label that doesn't match, or doesn't relate to, the text a sighted user actually sees on the button. This violates 2.5.3 Label in Name (Level A) directly, and it breaks something specific: voice-control users, who navigate by saying a button's visible label out loud — "click submit" — to activate it. If the accessible name is something else entirely, their voice command fails, because the software is listening for the accessible name, not what's printed on the screen.

3. aria-hidden="true" swallowing focusable content. This one creates a genuinely bizarre bug: a container gets aria-hidden="true" — often to hide a decorative wrapper or a closed panel — but a focusable element (a link, a button) lives inside it. The result is a "ghost" element: hidden from assistive technology entirely, while still perfectly reachable by Tab. A screen reader user tabs into a control that was never announced, with no idea what they just focused.

4. Aria-live regions firing too often. aria-live regions are meant to announce important, infrequent updates — a form error, a "item added to cart" confirmation. Overused, they turn into a firehose: every minor state change gets announced, and the one update that actually mattered gets buried in noise the user has learned to tune out.

5. Half-built custom widgets. A custom tab panel gets the right ARIA roles (role="tablist", role="tab", role="tabpanel") but nobody implements arrow-key navigation between tabs, which the ARIA Authoring Practices Guide specifies as expected behavior for that role. It looks right in the accessibility tree. It doesn't behave right for the person actually using a keyboard.

The One Category Where ARIA Is Nearly Always a Win

Not every use of ARIA carries this risk. Landmarks are the exception worth calling out on their own: role="navigation", role="main", role="banner" — or, better, their native HTML5 equivalents <nav>, <main>, <header>.

Landmarks are one of the highest-value, lowest-risk accessibility investments available. They let a screen reader user jump directly to the navigation, or straight to the main content, instead of tabbing or reading through every single element on the page in linear order. There's no keyboard behavior to hand-build, no focus management to get wrong — you're just labeling regions that already exist. Every page should have them.

The Safe Order of Operations

Here's the sequence that keeps ARIA a tool instead of a liability:

  • Start with native HTML. If a <button>, <a href>, or <input> can do the job, use it. You get correct role, keyboard support, and focus handling with no extra code.
  • Reach for ARIA only for what HTML can't express — custom comboboxes, tab panels, modal dialogs, live status regions.
  • If you add an ARIA role, own the whole contract. The WAI-ARIA Authoring Practices Guide documents the exact keyboard and focus behavior expected for every role. Adding the role without implementing that behavior is how "fixes" like the one that opened this article end up shipping.
  • Test with a keyboard, not just a screen reader announcement. If it sounds right but doesn't respond to the keys a real user would press, it's not done.

The Round-Up

ARIA is not a sprinkle-on fix for accessibility findings. It's a contract: the moment you add a role, you've promised assistive technology — and the person relying on it — that the element behaves the way that role is supposed to behave. Announce "button" without the keyboard handling to back it up, and you haven't fixed anything. You've built a more convincing trap.

The rule that prevents most of this damage fits in one sentence, straight from the W3C itself: no ARIA is better than bad ARIA. Start with native HTML, use ARIA only where HTML genuinely falls short, and when you do use it, implement the whole thing — not just the label.

If you want a real audit of where your ARIA is helping, where it's quietly failing 4.1.2, and where a native HTML element would have solved the problem in one line, start here.