ARIA: Accessible Rich Internet Applications, Roles, States

ARIA adds accessibility info to dynamic UIs via roles, states, properties — for screen readers when HTML alone isn't enough.

What is ARIA?

ARIA (Accessible Rich Internet Applications) is a W3C specification that adds accessibility information to web pages and applications via HTML attributes. It tells assistive technologies (screen readers, voice control, switch devices) what dynamic UI elements are, their state, and how they behave — when HTML alone doesn't carry that meaning.

ARIA was created because HTML elements like <button>, <input>, <a> are accessible by default, but custom widgets (modals, tabs, autocomplete, drag-drop, tree views) built with <div> and <span> are invisible to assistive tech without help. ARIA bridges that gap.

The three categories of ARIA attributes

TypePurposeExample
RolesWhat the element ISrole="button", role="tablist"
PropertiesAttributes describing the elementaria-label="Close", aria-haspopup="true"
StatesCurrent dynamic statearia-expanded="true", aria-checked="false"

The first rule of ARIA: don't use ARIA

If a native HTML element exists with the semantics you need, use it. Native elements are accessible by default; ARIA is harder to get right.

<!-- BAD: ARIA on div -->
<div role="button" tabindex="0" onclick="..">Submit</div>

<!-- GOOD: native button -->
<button onclick="..">Submit</button>

ARIA is for things HTML can't express natively (custom tabs, comboboxes, etc.).

Common ARIA roles

RoleFor
role="button"Custom buttons (when not using <button>)
role="dialog"Modal dialogs
role="tablist" + role="tab" + role="tabpanel"Tab UI
role="menu" + role="menuitem"Application menus
role="combobox"Autocomplete inputs
role="tree"Tree views
role="alert"Error messages, important notifications
role="status"Non-critical status updates
role="navigation"Navigation regions (or use <nav>)
role="main"Main content (or use <main>)

Common ARIA properties

PropertyUse
aria-labelAccessible name (when no visible label)
aria-labelledbyReference an element that names this
aria-describedbyReference a longer description
aria-hidden="true"Hide from assistive tech
aria-haspopupElement triggers a popup
aria-controlsElement controls another by ID
aria-currentCurrent item in a set (page, step, etc.)

Common ARIA states

StateUse
aria-expandedDisclosure / accordion / dropdown open?
aria-selectedTab / option selected?
aria-checkedCheckbox / radio state
aria-disabledElement disabled?
aria-pressedToggle button state
aria-busyElement being updated
aria-invalidForm field has invalid value

Live regions: announce dynamic updates

Tells screen readers when content changes (e.g., "message sent", error appeared).

<!-- Polite: wait for current speech to finish -->
<div aria-live="polite" aria-atomic="true">
  {{ savedMessage }}
</div>

<!-- Assertive: interrupt immediately (use sparingly) -->
<div aria-live="assertive">
  {{ errorMessage }}
</div>

<!-- role="alert" is shorthand for aria-live="assertive" -->
<div role="alert">Error: connection lost</div>

Real-world example: accessible tabs

<div role="tablist" aria-label="Account sections">
  <button role="tab" aria-selected="true" aria-controls="profile-panel" id="profile-tab">
    Profile
  </button>
  <button role="tab" aria-selected="false" aria-controls="billing-panel" id="billing-tab">
    Billing
  </button>
</div>

<div role="tabpanel" id="profile-panel" aria-labelledby="profile-tab">
  Profile content
</div>
<div role="tabpanel" id="billing-panel" aria-labelledby="billing-tab" hidden>
  Billing content
</div>

ARIA best practices

  • Use native HTML first. Don't recreate <button> with ARIA.
  • Don't change native semantics. Don't put role="button" on a <a>.
  • All interactive ARIA must be keyboard-accessible. Tabindex + key handlers.
  • Don't hide focusable elements. aria-hidden="true" on a button = broken.
  • Provide visible labels. aria-label is for icon-only buttons; visible text is better.
  • Test with screen reader. NVDA, JAWS, VoiceOver — what you intended ≠ what they announce.
  • Follow APG patterns. WAI-ARIA Authoring Practices Guide has tested patterns.
  • Update states as UI changes. aria-expanded must flip when accordion opens.

Common ARIA pitfalls

  • Wrong ARIA over right HTML. Most common mistake.
  • aria-hidden on focusable elements. Element is focusable but invisible to AT = confusing.
  • Stale states. aria-expanded="false" stays as menu opens.
  • Overuse of role="application". Disables browser shortcuts; rarely correct.
  • Live regions firing too often. Annoying; use sparingly.
  • Missing keyboard support. ARIA without keyboard = unusable.
  • aria-label conflicting with visible text. Confusing; match them or omit.

FAQ: ARIA

Should I use ARIA on every element?

No — only when native HTML doesn't express the semantics you need. Native HTML is accessible by default.

What's the "first rule of ARIA"?

"Don't use ARIA" — if a native HTML element does the job, use it instead.

Does ARIA help SEO?

Indirectly. Search engines may use semantic info; the bigger SEO win is from accessible markup overall.

What's WAI-ARIA APG?

Authoring Practices Guide — tested patterns for common widgets (combobox, dialog, tabs). Use these instead of inventing.

Can I use ARIA on SVG?

Yes. <svg role="img" aria-labelledby="title"> with a <title> child.

What's aria-current?

Marks the current item in a set: aria-current="page" on the active nav link.

How do I test ARIA?

Automated tools (axe, Lighthouse) catch some errors. Manual: keyboard nav + screen reader (NVDA, VoiceOver).

Test ARIA + accessibility with LoadFocus

LoadFocus runs Lighthouse audits including the Accessibility audit, flagging many ARIA mistakes from 25+ regions. Sign up free at loadfocus.com/signup.

How fast is your website?

Elevate its speed and SEO seamlessly with our Free Speed Test.

Free Website Speed Test

Analyze your website's load speed and improve its performance with our free page speed checker.

×