Learning objectives
Choose native controls; distinguish name, role, state, and description; synchronize ARIA state with visible behavior.
Prerequisites
Understand headings, landmarks, labels, and keyboard focus. Basic JavaScript helps with the disclosure example.
Start with the browser’s built-in contract
A native button exposes a button role and supports familiar keyboard activation. An anchor with href is a link. A labeled input exposes its purpose and value. These elements reduce the amount of behavior an author must implement and give assistive technologies information beyond the painted pixels.
ARIA supplies roles, states, and relationships when native semantics do not fully express an interface. It does not add keyboard handling, move focus, validate a form, or create a visual design. A div with role="button" still needs all expected button behavior. Using a real button is usually simpler and more reliable.
Name the control before describing it
An accessible name identifies an element, such as Search catalogue. A description adds instructions, such as Search by title or author. Native labels, visible button text, and meaningful link content should be the first choice. Aria-labelledby can reference visible text elsewhere, while aria-describedby connects supplementary information.
Aria-label supplies a name directly, but it can hide or replace useful text in the accessibility calculation. If the visible label says Save and the accessible name says Submit profile, speech-input users may not be able to activate the control by the words they see. Keep names aligned with visible wording.
Aria-hidden removes content from accessibility exposure; it does not visually hide it or prevent keyboard focus. Applying it to a focusable control creates a contradiction. Use it for genuinely redundant decorative content, and avoid placing interactive descendants inside a hidden accessibility subtree.
Keep state and behavior synchronized
A disclosure button can use aria-expanded to describe whether its controlled content is open and aria-controls to identify the content. When the button changes the visible state, update aria-expanded in the same operation. A stale value tells one group of users the opposite of what another group sees.
Use live regions sparingly for changes that would otherwise be missed. A status region suits a non-urgent update, while more interruptive announcements require a clear reason. Do not announce every character typed or duplicate a message in several live regions.
Test the real interaction with keyboard, zoom, and assistive technology. Automated checks can catch missing names or invalid attributes but cannot decide whether the words are helpful, the focus sequence is sensible, or the workflow can be completed. Accessibility is a property of the complete experience, not a count of ARIA attributes.
Working example
<button type="button" id="help-toggle" aria-expanded="false" aria-controls="help-panel">Show booking help</button>
<div id="help-panel" hidden><p>Your booking reference appears in the confirmation email.</p></div>
Another example
<button type="button"><span aria-hidden="true">+</span> Add a book</button>
<p id="search-hint">Search by title or author.</p>
<label for="book-search">Search catalogue</label>
<input id="book-search" type="search" aria-describedby="search-hint">
Expected output
The live button reveals the help panel and updates its expanded state. The decorative plus sign does not repeat in the second button’s accessible name, while the search field has separate label and help text.
Common mistakes
Do not add ARIA roles to every element. Do not use aria-hidden on focusable controls. Do not assume aria-disabled prevents clicks or aria-required performs validation. Native disabled and required attributes have actual browser behavior where supported.
Accessibility and browser notes
Inspect the accessibility tree to see the computed name and role, then verify behavior with actual keyboard interaction. Use published ARIA patterns when building complex widgets and test the browser/assistive-technology combinations your audience uses.
Practice
Create a button with a visible label and an optional decorative icon. Explain why a separate aria-label is unnecessary.
Review the solution and reasoning
<button type="button"><span aria-hidden="true">✓</span> Mark lesson complete</button>
The visible text already supplies the action name. Hiding the decorative check avoids redundant announcement. The button still needs its application action, but its native keyboard behavior and role are present.