Identify the user task
Is the user navigating, submitting, selecting, toggling, expanding, editing, or issuing an application command?
Implementation handbook
Use native HTML first. Add ARIA only when semantics, states, or relationships are otherwise missing. Every explicit role carries a keyboard, focus, state, and testing obligation.
An incorrect role can override reliable browser semantics and create a false interaction model for assistive technology.
01 · Decision model
Follow this sequence for every interactive component. A visual design should not determine the role.
Is the user navigating, submitting, selecting, toggling, expanding, editing, or issuing an application command?
Prefer button, a, input, select, details, dialog, and table.
Add only the missing name, state, relationship, live announcement, or custom-widget role.
Match keyboard navigation, focus movement, activation, cancellation, selection, and disabled behavior.
The visual state, DOM state, ARIA state, and application state must describe the same condition.
Inspect keyboard operation, focus order, announcements, zoom, reflow, contrast, and real assistive technology.
role="button" promises button behavior. It does not create Enter or Space activation, focusability, disabled behavior, or form semantics.
02 · Role catalog
Search the catalog by role, native equivalent, required behavior, or category.
Showing all roles.
| Role | Category | Native first | Use when | Primary obligation |
|---|---|---|---|---|
button |
Widget | <button> |
A non-native element must act as a button. | Focus, Enter and Space activation, disabled behavior. |
checkbox |
Widget | <input type="checkbox"> |
A custom binary or tri-state selection is unavoidable. | aria-checked, Space activation, label, focus. |
radio |
Widget | <input type="radio"> |
A custom mutually exclusive option is unavoidable. | Group semantics, checked state, arrow-key model. |
switch |
Widget | Checkbox or button | The binary state is explicitly understood as on or off. | aria-checked, stable label, immediate state change. |
slider |
Widget | <input type="range"> |
A custom continuous-value control is essential. | Arrow/Home/End keys, min/max/current value, orientation. |
tablist |
Composite | Buttons may be sufficient | Mutually exclusive panels share one local context. | Roving focus, arrow keys, selection and panel linkage. |
menu |
Composite | Disclosure plus links | An application command menu behaves like desktop software. | Managed focus, arrow keys, Escape, type-ahead. |
listbox |
Composite | <select> |
Native select cannot meet the interaction requirement. | Managed focus, selection, type-ahead, option ownership. |
combobox |
Composite | Input plus datalist/select | An editable or selectable popup requires custom behavior. | Popup state, focus strategy, active option, keyboard model. |
grid |
Composite | <table> |
Cells are interactive like a spreadsheet. | Two-dimensional focus, row/cell semantics, edit mode. |
main |
Landmark | <main> |
Normally implicit through native HTML. | One primary main landmark per rendered page. |
navigation |
Landmark | <nav> |
Identify a significant navigation group. | Distinct labels when multiple navigation landmarks exist. |
search |
Landmark | <search> or labelled form |
Identify site or application search. | Clear landmark name when multiple search regions exist. |
region |
Landmark | Named <section> |
Content is a significant navigation destination. | Accessible name and restraint to avoid landmark overload. |
heading |
Structure | <h1>–<h6> |
Usually only for environments without native headings. | Correct level and document outline. |
list |
Structure | <ul> or <ol> |
Native list markup is unavailable. | Correct list-item ownership and meaningful grouping. |
status |
Live region | No direct equivalent | Routine dynamic information should be announced politely. | Update an existing region; do not move focus. |
alert |
Live region | No direct equivalent | An urgent condition requires immediate awareness. | Use sparingly; avoid interrupting routine work. |
dialog |
Window | <dialog> |
A focused task appears in a separate window context. | Name, initial focus, containment, Escape, focus return. |
alertdialog |
Window | <dialog> |
A brief urgent decision requires immediate response. | Concise message, explicit choices, disciplined focus. |
command |
Abstract | Never author directly | Only defines the ARIA ontology. | Do not use abstract roles in content. |
03 · State model
Roles answer “what is this?” These attributes communicate identity, condition, and connection.
| Attribute | Purpose | Typical use | Critical rule |
|---|---|---|---|
aria-labelledby |
Names an element using visible text elsewhere. | Dialog, region, control group. | Prefer visible labels over hidden-only names. |
aria-describedby |
Adds supplementary description. | Help text, constraints, validation explanation. | Do not use description as a substitute for a label. |
aria-expanded |
Reports whether controlled content is open. | Disclosure, accordion, menu button. | Place it on the controlling element and synchronize it. |
aria-controls |
Identifies controlled content. | Disclosure, tabs, accordion. | It describes a relationship; it implements no behavior. |
aria-current |
Marks the current item in a related set. | Page, step, date, location. | Do not confuse current with selected. |
aria-selected |
Marks selection inside a composite widget. | Tab, option, grid cell. | Selection and keyboard focus may be different states. |
aria-pressed |
Reports a toggle-button state. | Bold, mute, pin, favorite. | Keep the button label stable while the state changes. |
aria-checked |
Reports checkbox, radio, or switch state. | Custom selection controls. | Native checked state is preferable when available. |
aria-invalid |
Reports a value that failed validation. | Form field. | Connect the field to a specific error message. |
aria-busy |
Reports that a region is being updated. | Refreshing results or data panels. | Clear it when the update is complete. |
checked plus aria-checked="false" creates an invalid state model. Native HTML state takes priority.
04 · Runnable patterns
These examples are deliberately small. Each demonstrates the semantic baseline, state owner, keyboard behavior, and focus strategy.
Use for ordinary website navigation. Do not convert a group of links into an application menu.
aria-expanded on the button mirrors hidden on the panel.<button
type="button"
aria-expanded="false"
aria-controls="resources-panel"
>
Resources
</button>
<div id="resources-panel" hidden>
<a href="/guides">Guides</a>
</div>
Use only for mutually exclusive panels. A row of content filters is not automatically a tab interface.
tablist owns tab elements; each tab controls a tabpanel.aria-selected="true"; inactive tabs use tabindex="-1".Native dialog provides the window primitive. The application still owns naming, focus placement, cancellation, and return.
<dialog> opened with showModal().aria-labelledby references the visible heading.Routine updates should be announced without moving focus or interrupting the user.
status supplies polite live-region behavior.Use when the product language clearly describes an immediate on/off setting. A native checkbox is still the safer default.
Setting is off.
aria-checked changes; the visible label remains stable.05 · Page structure
Landmarks are navigation destinations, not visual containers. Too many named regions produce a noisy, flat page map.
<main>.<nav>.role="main" to <main>.<nav> for every list of links.<a class="skip-link" href="#main-content">Skip to main content</a>
<header>…</header>
<nav aria-label="Primary">…</nav>
<main id="main-content">…</main>
<aside aria-labelledby="related-title">
<h2 id="related-title">Related resources</h2>
</aside>
<footer>…</footer>
06 · Forms
A field label identifies the control. Help text explains constraints. An error explains what must be corrected.
The error is connected with aria-describedby. Invalid state appears only after validation.
label associated through for and id.aria-invalid appears only after failure and is removed after correction.07 · Failure modes
These patterns often look correct visually while exposing a broken accessibility model.
<div role="button"> by defaultIt recreates behavior the browser already implements. Use a native button.
menuAn ARIA menu promises a desktop command-menu keyboard model. Ordinary links should remain ordinary links.
aria-hidden="true"Keyboard focus can enter content that assistive technology cannot perceive.
A visual panel opens while aria-expanded remains false. State synchronization is part of the component contract.
tabindexManual focus ordering becomes fragile as the DOM evolves. Use meaningful source order and roving focus only inside composite widgets.
role="alert" can interrupt current speech. Use status for ordinary confirmations and progress messages.
A grid introduces two-dimensional focus and editing expectations. Use native table markup for tabular information.
08 · CSS foundation
The reset removes inconsistent assumptions. The base and layout layers then restore intentional spacing, focus, overflow, and control geometry.
border-box sizing.role="list".appearance: none.all: unset.html { font-size: 62.5%; }.@layer reset {
*, *::before, *::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
text-size-adjust: 100%;
tab-size: 4;
}
body { margin: 0; }
:where(h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd) {
margin: 0;
}
:where(ul[role="list"], ol[role="list"]) {
margin: 0;
padding: 0;
list-style: none;
}
:where(button, input, select, textarea) {
font: inherit;
color: inherit;
letter-spacing: inherit;
}
::file-selector-button { font: inherit; }
:where(img, picture, video, canvas) {
display: block;
max-inline-size: 100%;
}
:where(img, video) { block-size: auto; }
svg { max-inline-size: 100%; }
}
This guide uses intrinsic auto-fit grids, min-inline-size: 0, bounded horizontal scrolling for tables and code, safe-area padding, 44-pixel controls, explicit square-button geometry, and one sticky header on mobile.
09 · Delivery gate
Progress is stored locally in this browser. Use the checklist as a pull-request and design-review contract.
The component begins with the most appropriate HTML element.
Visible text, labels, and accessible names describe the same user task.
Visual, DOM, ARIA, and application state remain synchronized.
Tab, Enter, Space, Escape, Arrow, Home, and End behavior match the role.
Focus entry, movement, visibility, containment, and return are intentional.
Content remains usable at 200% text resize and a 320 CSS-pixel viewport.
Text, boundaries, states, and focus remain perceptible without relying on color alone.
The accessibility tree, announcements, labels, role, value, and state are verified.
10 · Validation strategy
Automation catches structural defects. Human testing verifies whether the experience is coherent and operable.
HTML conformance
↓
Static accessibility linting
↓
axe-core component tests
↓
Browser keyboard tests
↓
Focus and state assertions
↓
Manual assistive-technology testing
Require specialized accessibility review for comboboxes, listboxes, menus, trees, grids, rich-text editors, carousels, command palettes, drag-and-drop editors, and interactive canvas or diagram experiences.
11 · Standards
The guide uses current W3C recommendations as the production baseline and treats working drafts as horizon signals.
Defines valid role and aria-* usage on HTML elements. W3C Recommendation published April 15, 2026.
Production role, state, property, and accessibility API mapping model.
Keyboard, focus, naming, landmark, and widget-pattern implementation guidance.
Product-level accessibility requirements, including focus, target size, dragging alternatives, reflow, and status messages.
Guidance for combining automated checks with knowledgeable human evaluation.
Platform preference detection for reducing or replacing non-essential animation.