The five rules of ARIA
Including the one rule that, if you remember nothing else, will save you from breaking accessibility.
ARIA is a set of HTML attributes that lets you tell assistive technologies — screen readers, voice control, switch devices — what your custom UI is and what it's doing. It looks like power. It also looks like a footgun, and most of the time it is one.
This lesson is about a short list, written by the people who maintain the ARIA spec, called the five rules of ARIA. The whole list fits on a sticky note. The first rule is the one that surprises people, so let's start there: the best ARIA is usually no ARIA at all.
What ARIA actually is
ARIA stands for Accessible Rich Internet Applications. The acronym is a mouthful; what it does is simple. ARIA attributes don't change how a page looks and don't change what it does in JavaScript. They only change what assistive technologies report to the user.
A screen reader, for instance, reads the page through something called the accessibility tree — a parallel structure built from your HTML plus any ARIA you added. If you write <button>Send</button>, the accessibility tree already says "Send, button". If you write <div onclick="...">Send</div>, the tree says "Send" — and the user has no idea it's a button. ARIA can patch the second case. It cannot patch a missing keyboard handler, missing focus, or missing styles.
ARIA only changes what's announced. It does not add behavior. A div with role="button" is still a div until you wire up Enter, Space, focusability, and styles yourself.
Rule 1: If you can use a native element, do
This is the rule everyone forgets in the moment. The exact wording from the spec is: "If you can use a native HTML element with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state or property, do so."
Translated: prefer <button> over <div role="button">. Prefer <input type="checkbox"> over <div role="checkbox" aria-checked="false">. Prefer <nav>, <main>, <details>, <dialog> over their ARIA equivalents. Native elements give you focus, keyboard, state, and announcements — for free, and consistently across browsers.
The reason this matters: ARIA is only a promise. When you write role="checkbox", you're promising the screen reader that this thing acts like a checkbox — clickable with Space, has a checked state, focusable. If your code doesn't keep that promise, the user is now lied to, which is worse than not knowing.
<!-- Bad: a div pretending to be a button --> <div role="button" tabindex="0" onclick="send()">Send</div> <!-- Good: an actual button --> <button onclick="send()">Send</button>
Rule 2: Don't change native semantics unless you really have to
If an element already has a role baked in — <h1> is a heading, <a> is a link, <nav> is a navigation landmark — don't put ARIA on top to change it. The classic mistake:
<h1 role="button">Welcome</h1>
That's now a button to assistive tech, but a heading to everything else. The page outline breaks. Browsers and screen readers will fight you. If you need a button, put a button inside the heading — don't replace one with the other.
Rule 3: All interactive ARIA controls must be usable with the keyboard
Anything with an interactive role — role="button", role="tab", role="checkbox", role="menuitem" — must be reachable with Tab and operable with the keys a user expects for that role. Buttons activate on Enter and Space. Checkboxes toggle on Space. Tabs move with arrow keys. The role tells the user "this is a button"; the keyboard has to deliver on that.
Rule 4: Don't use role="presentation" or aria-hidden="true" on focusable elements
role="presentation" (and the equivalent role="none") tells assistive tech "ignore my role". aria-hidden="true" says "ignore me entirely". If you put either of those on something that can still receive focus, a keyboard user will tab to a thing that, to a screen reader, doesn't exist. They land somewhere and the screen reader says nothing, or worse, says something that makes no sense.
The fix is to either remove the focus (no tabindex, not a focusable element) or remove the hiding. You can't have both.
This is one of the most common ARIA bugs in the wild. Hiding a button with aria-hidden="true" while leaving it tabbable creates a "ghost focus" — visible to sighted keyboard users, invisible to screen readers.
Rule 5: All interactive elements must have an accessible name
The accessible name is what the screen reader announces when focus lands on a control: "Submit, button" or "Search, edit". Every interactive element needs one. For a <button>Send</button>, the text content is the name. For an icon-only button — a magnifying-glass SVG with nothing else inside — there is no text, so you have to provide one with aria-label="Search" or visually hidden text.
Lesson 3 covers all the ways to give something a name. For now, just remember: a control with no name is a control no one can describe. Voice users can't say "click Submit" if Submit has no name.
Try it yourself
<div role="button" tabindex="0">Save</div>. Per rule 1, what should you do first?aria-hidden="true" on a visible "Close" button to "clean up the screen reader output." What's wrong?<h2 role="tab">Settings</h2>. Which rule does this violate?