Tags: web-dev ux concept

ARIA

Date: 2026-08-17


ARIA (Accessible Rich Internet Applications) is a set of attributes that override what the accessibility tree reports about an element. Its own first rule is not to use it — a native element carries the role, the state, the keyboard behaviour and the focus handling for free, and ARIA supplies only the first two.


The five rules, and what they mean in practice

The specification states them; only the first and the last get quoted, so here they all are with the consequence attached:

1  USE A NATIVE ELEMENT if one exists with the semantics you need
     → <button> over <div role="button">. always

2  DON'T CHANGE NATIVE SEMANTICS unless you must
     → <h2 role="button"> breaks heading navigation for screen reader users

3  ALL INTERACTIVE ARIA CONTROLS MUST BE KEYBOARD OPERABLE
     → role="button" without tabindex and a key handler is a lie

4  DON'T USE role="presentation" OR aria-hidden ON A FOCUSABLE ELEMENT
     → produces something reachable by keyboard but invisible to
       screen readers. the worst possible state

5  EVERY INTERACTIVE ELEMENT NEEDS AN ACCESSIBLE NAME
     → an icon button with no text and no aria-label is announced
       as "button", which is useless

Rule 3 is the one that catches people. ARIA changes what is announced. It changes nothing about behaviour.

<!-- announced as a button. does nothing on Enter or Space.
     not focusable. not in the tab order. -->
<div role="button" onclick="submit()">Continue</div>
 
<!-- to make that div behave, you must write ALL of this -->
<div role="button" tabindex="0"
     onclick="submit()"
     onkeydown="if (event.key === 'Enter' || event.key === ' ') {
                  event.preventDefault(); submit();
                }">Continue</div>
 
<!-- or, instead of all of it -->
<button type="button" onclick="submit()">Continue</button>

The <button> gets focus, tab order, Enter and Space activation, the disabled state, form association, and the platform’s own focus ring — none of which ARIA provides.

The attributes worth knowing

AttributeDoesNote
roleOverrides what the element isUse sparingly
aria-labelSupplies a name where there’s no visible textIcon buttons
aria-labelledbyNames it from other elements’ textPreferred over aria-label where visible text exists
aria-describedbyAttaches supplementary textError messages, hints
aria-expandedOpen/closed state of a disclosureThe most-forgotten one
aria-current”This is the current page/step”Navigation, breadcrumbs
aria-liveAnnounces dynamic changesSee below
aria-hiddenRemoves from the accessibility treeNever on anything focusable
aria-invalidMarks a field as failing validationPair with aria-describedby

Naming precedence, since it causes confusion: aria-labelledby beats aria-label, which beats the element’s own text content. So an aria-label silently overrides visible text — and if the two disagree, a voice-control user asking for the button by its visible name can’t activate it.

Live regions

The one thing ARIA does that no native element does: announce a change that happens without a page navigation.

<!-- polite: waits for a pause. use for almost everything -->
<div aria-live="polite" role="status">Added to basket</div>
 
<!-- assertive: interrupts immediately. errors and warnings ONLY -->
<div aria-live="assertive" role="alert">Payment declined</div>

The element must exist in the DOM before the content changes. Inserting a live region and its text at the same moment usually announces nothing — render the empty container on load, then update its contents.

This is essential for single-page commerce: adding to basket, applying a discount code, filtering results and validation failures all change the page silently for a screen reader user without one — Screen Readers, Feedback and System Status.

Where ARIA is genuinely required

Native HTML doesn’t cover everything, and these need it:

  • Tabs, accordions, comboboxes, tree views — no native equivalent. Follow the ARIA Authoring Practices patterns rather than inventing the attribute set, and use a tested headless component library rather than writing them
  • Live regions, as above
  • State on custom widgets — aria-expanded, aria-selected, aria-pressed
  • Relationships the DOM order doesn’t express — aria-describedby linking a field to an error message elsewhere on the page — Accessible Forms
  • Landmark regions where the native elements aren’t available, though <nav>, <main>, <aside> and <header> cover most of it — Semantic HTML

The failure worth naming

Bad ARIA is worse than no ARIA. No ARIA means a screen reader falls back to the element’s real semantics, which are at least honest. Wrong ARIA actively misinforms.

<div role="button">              announced as a button.
  no tabindex, no key handler    cannot be reached or activated by keyboard.
                                 → a keyboard user is told there's a control
                                   and given no way to use it

<span aria-hidden="true">        hidden from screen readers.
  <button>Buy</button>           still focusable by keyboard.
</span>                          → tab lands on something that announces
                                   nothing at all

Both are common, both come from adding ARIA to look thorough, and both are more damaging than the plain markup would have been.

Checking it

  • Automated tooling catches perhaps a third of issues — invalid attribute values, missing names, contrast. Necessary, not sufficient — Accessibility Testing
  • Tab through the page. Everything interactive reachable, focus visible, order sensible — Keyboard Navigation, Focus Management
  • Inspect the accessibility tree in DevTools, which shows what’s actually reported rather than what you wrote — The Accessibility Tree
  • Listen to it. Fifteen minutes with a real screen reader is worth more than any audit report

Where it interacts

  • The Accessibility Tree — the structure ARIA modifies, and the thing to inspect when it doesn’t behave
  • Semantic HTML — the alternative that rule 1 points at, and the right answer most of the time
  • WCAG — the conformance standard ARIA is used to meet
  • Web Components — shadow DOM breaks ID-based ARIA relationships, which is a real constraint on custom widgets