Skip to main content

ARIA Roles & Attributes

ARIA (Accessible Rich Internet Applications) is a set of HTML attributes that communicate the role, state, and properties of elements to assistive technologies. It bridges the gap when native HTML elements are not enough for complex interactive patterns.

The Rules of ARIA

Before using ARIA, remember these rules from the W3C:

  1. Do not use ARIA if you can use native HTML. A <button> is always better than <div role="button">.
  2. Do not change native semantics unless absolutely necessary. Do not put role="heading" on a <button>.
  3. All interactive ARIA elements must be keyboard accessible. If you add role="button", you must handle Enter and Space key events.
  4. Do not use role="presentation" or aria-hidden="true" on focusable elements. This hides them from screen readers while keeping them in the tab order, creating a confusing experience.

Common ARIA Roles

When you build custom widgets that have no native HTML equivalent, use roles to communicate purpose:

<!-- Tab interface -->
<div role="tablist">
  <button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
  <button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
</div>
<div role="tabpanel" id="panel-1">Content for tab 1</div>
<div role="tabpanel" id="panel-2" hidden>Content for tab 2</div>

Other useful roles include dialog, alertdialog, menu, menuitem, tooltip, and tree.

Essential ARIA Attributes

aria-label and aria-labelledby

Use these when a visible label is not present or when you need to override the visible text:

<!-- aria-label: provides a label directly -->
<button aria-label="Close dialog">
  <svg><!-- X icon --></svg>
</button>

<!-- aria-labelledby: references another element's text -->
<h2 i="dialog-title">Delete Account</h2>
<div rol="dialog" aria-labelledb="dialog-title">
  <p>This action cannot be undone.</p>
</div>

aria-describedby

Links an element to additional descriptive text:

<label for="username">Username</label>
<input type="text" id="username" aria-describedby="username-help" />
<p id="username-help">Must be 3-20 characters, letters and numbers only.</p>

aria-expanded

Communicates whether a collapsible section is open or closed:

<button aria-expanded="false" aria-controls="menu">Menu</button>
<ul id="menu" hidden>
  <li><a href="/about">About</a></li>
  <li><a href="/contact">Contact</a></li>
</ul>

Toggle aria-expanded between "true" and "false" with JavaScript as the menu opens and closes.

aria-hidden

Removes an element from the accessibility tree while keeping it visually present. Useful for decorative elements:

<!-- Decorative icon next to text  screen reader ignores the icon -->
<span aria-hidden="true">🎨</span>
<span>Design Tools</span>

Never use aria-hidden="true" on elements that contain focusable children.

Live Regions

Live regions announce dynamic content changes to screen reader users. This is critical for notifications, chat messages, and form validation errors:

<!-- Polite: waits until the user is idle to announce -->
<div aria-live="polite" aria-atomic="true">
  3 items in your cart
</div>

<!-- Assertive: interrupts the user immediately -->
<div role="alert">
  Your session will expire in 2 minutes.
</div>

The role="alert" shorthand is equivalent to aria-live="assertive". Use it sparingly — interrupting users too often is a poor experience.

Key live region attributes:

  • aria-live="polite" — announce when the user is idle
  • aria-live="assertive" — announce immediately
  • aria-atomic="true" — announce the entire region, not just the changed part
  • aria-relevant="additions text" — control which changes trigger announcements

Common Patterns

Disclosure (show/hide)

<button aria-expanded="false" aria-controls="details">
  Show Details
</button>
<div id="details" hidden>
  <p>Additional information here.</p>
</div>

Accessible Modal Dialog

<div role="dialog" aria-modal="true" aria-labelledby="modal-title">
  <h2 id="modal-title">Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <button>Confirm</button>
  <button>Cancel</button>
</div>

When aria-modal="true" is set, screen readers should confine navigation to the dialog content.

Best Practice

Always test ARIA additions with an actual screen reader. ARIA attributes are promises to assistive technology — if you add role="tab" but do not implement the expected keyboard behavior, you make the experience worse, not better.