Accessible Rich Internet Applications (WAI-ARIA)
WAI-ARIA supplies roles, states, and properties when native HTML cannot express a widget. The first rule of ARIA is to use native HTML instead; the second is not to change native semantics unnecessarily.
Core rules
- A role does not add keyboard behavior. You must implement focus management and key handling.
- Accessible name computation: aria-labelledby wins over aria-label, then native label/text. Do not put names on roles that prohibit naming (e.g., generic).
- aria-hidden="true" removes content from the accessibility tree; never use it on focusable elements.
- States must update: aria-expanded, aria-selected, aria-checked, aria-current. Properties such as aria-controls and aria-describedby create relationships.
- Live regions: role="status" (polite) and role="alert" (assertive) must exist before content changes; avoid assertive for routine updates.
- Dialogs: role="dialog", aria-modal="true", accessible name, focus moved in and returned, Escape to close.
Worked example
Custom tabs need role="tablist" on the container, role="tab" on each tab, role="tabpanel" on panels, aria-selected on tabs, aria-controls linking tab to panel, and roving tabindex: only the active tab is in the tab sequence; arrow keys move between tabs. Reasoning: ARIA communicates structure and state; the script must supply the keyboard model. Without roving tabindex, every tab becomes a stop, which is noisy and nonstandard.
Traps
aria-label on a plain div with no role; aria-hidden on a focusable link; live regions injected at the same time as their message; overusing ARIA instead of native elements; and setting aria-expanded but never toggling it.