ARIA Labels: When to Use Them and When to Avoid Them
ARIA can make your app more accessible — or actively harm screen reader users if misapplied. This guide explains the rules with practical before-and-after examples.
By ShipReady · Updated
ARIA (Accessible Rich Internet Applications) lets you describe UI to assistive technology when native HTML cannot. It is powerful and easy to misuse — so much so that the first rule of ARIA is: do not use ARIA if a native element will do.
When you do not need ARIA
Native elements come with the right semantics for free. A <button> is announced as a button, focusable, and keyboard-operable. A <nav>, a <label> tied to an input, a real heading — all of these are better than a <div> with ARIA bolted on, because the browser and screen reader already agree on what they are.
When ARIA earns its place
- Icon-only buttons that have no visible text — give them an aria-label.
- Live regions (aria-live) for content that updates without a page load, like toasts or validation.
- Custom widgets with no native equivalent — tabs, comboboxes, disclosure menus.
- Communicating state, such as aria-expanded on a toggle or aria-current on the active nav item.
aria-label vs aria-labelledby vs a real label
Three ways to name something, in the order you should reach for them.
| Use | When | Why it is preferred |
|---|---|---|
A visible <label for> | Any form input | Names the field for everyone, and clicking the label focuses the input — a usability win, not only an accessibility one. |
aria-labelledby | The name is already visible elsewhere on screen | Points at existing text, so the name cannot drift out of sync with what is displayed. |
aria-label | There is genuinely no visible text — an icon-only button | Invents a name that only assistive technology can see, which is why it goes last. |
The reason aria-label ranks last is that invisible text is untested text. Nobody proofreads it, translation pipelines routinely miss it, and it silently overrides any visible content inside the element — so a button reading "Delete" with aria-label="Close" is announced as "Close", and the two audiences are now looking at different products.
Common misuses
- Putting aria-label on a non-interactive <div> with no role — it may be ignored or confusing.
- Redundant roles like <button role="button"> that add noise.
- Using aria-hidden on something that is still keyboard-focusable, stranding screen reader users.
How to check a component in thirty seconds
- Tab to the element. If you cannot reach it with a keyboard, no ARIA attribute will save it — that is a different and more serious bug.
- Open the accessibility tree in developer tools (Chrome: Elements, then the Accessibility pane) and read the computed Name and Role. That is what a screen reader announces.
- Ask whether the name would make sense read aloud with no surrounding context. "Button" fails. "Delete invoice 4021" passes.
- Remove the ARIA and check whether a native element would have given you the same result. If it would, use the native element.
That last step is the first rule of ARIA, and it is a rule rather than a preference: no ARIA is better than bad ARIA. A native <button> arrives with a role, keyboard operability, focus behaviour and platform conventions that every assistive technology already agrees on. A <div role="button"> gets you the role and nothing else — you now owe the keyboard handler, the focus management, and the Enter and Space key behaviour, and the bug reports arrive when you miss one.
The accessible name is the part machines can check
Most of ARIA is judgement. One part is not: whether an element has an accessible name at all. A button with no text and no aria-label is announced as "button" and nothing else, and that is a straightforward, checkable defect rather than a matter of taste.
ShipReady checks the naming failures it can see in the HTML of every page it crawls: form inputs with no associated label, images with no alt attribute, iframes with no title, and headings that are empty. It does not run your page in a browser, so it cannot compute the final accessible name for a custom widget — for that, use an in-browser checker and the screen-reader pass described in the WCAG 2.2 guide.