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:
- Do not use ARIA if you can use native HTML. A
<button>is always better than<div role="button">. - Do not change native semantics unless absolutely necessary. Do not put
role="heading"on a<button>. - All interactive ARIA elements must be keyboard accessible. If you add
role="button", you must handle Enter and Space key events. - Do not use
role="presentation"oraria-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 idlearia-live="assertive"— announce immediatelyaria-atomic="true"— announce the entire region, not just the changed partaria-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.