Aria Patterns
ARIA roles, states, and properties for building accessible custom widgets and UI components
You are an expert in ARIA roles and patterns for building accessible web applications. ## Key Points 1. Use native HTML instead of ARIA whenever possible. 2. Do not change native semantics unless absolutely necessary. 3. All interactive ARIA controls must be keyboard operable. 4. Do not use `role="presentation"` or `aria-hidden="true"` on visible, focusable elements. 5. All interactive elements must have an accessible name. - **Roles**: Define what an element is (e.g., `role="dialog"`, `role="tab"`, `role="alert"`). - **States**: Describe the current condition (e.g., `aria-expanded="false"`, `aria-checked="true"`). - **Properties**: Provide additional semantics (e.g., `aria-label`, `aria-describedby`, `aria-required`). - Inspect the accessibility tree in Chrome DevTools (Elements > Accessibility) or Firefox (Accessibility Inspector) to verify computed roles and names. - Use the axe browser extension to flag misused ARIA attributes. - Test with a screen reader to confirm that roles and states are announced correctly during interaction. - Validate that every `aria-controls`, `aria-labelledby`, and `aria-describedby` reference points to an existing element ID. ## Quick Example ```html <!-- Automatically announced by screen readers when content appears --> <div role="alert"> <p>Error: Your password must be at least 8 characters.</p> </div> ```
skilldb get accessibility-skills/Aria PatternsFull skill: 162 linesARIA Patterns — Web Accessibility
You are an expert in ARIA roles and patterns for building accessible web applications.
Core Philosophy
Overview
Accessible Rich Internet Applications (ARIA) is a set of attributes that supplement HTML semantics to communicate roles, states, and properties of UI elements to assistive technologies. ARIA does not change behavior or appearance—it only changes what the accessibility tree exposes. The first rule of ARIA is: do not use ARIA if a native HTML element with the desired semantics already exists.
Core Concepts
The five rules of ARIA
- Use native HTML instead of ARIA whenever possible.
- Do not change native semantics unless absolutely necessary.
- All interactive ARIA controls must be keyboard operable.
- Do not use
role="presentation"oraria-hidden="true"on visible, focusable elements. - All interactive elements must have an accessible name.
ARIA categories
- Roles: Define what an element is (e.g.,
role="dialog",role="tab",role="alert"). - States: Describe the current condition (e.g.,
aria-expanded="false",aria-checked="true"). - Properties: Provide additional semantics (e.g.,
aria-label,aria-describedby,aria-required).
Landmark roles
| Role | HTML Equivalent | Purpose |
|---|---|---|
banner | <header> | Site header |
navigation | <nav> | Navigation links |
main | <main> | Primary content |
complementary | <aside> | Supporting content |
contentinfo | <footer> | Site footer |
search | <search> | Search functionality |
region | <section> (with label) | Generic labeled section |
Implementation Patterns
Disclosure (show/hide)
<button aria-expanded="false" aria-controls="details-panel">
Show details
</button>
<div id="details-panel" hidden>
<p>Additional information goes here.</p>
</div>
const button = document.querySelector('[aria-controls="details-panel"]');
const panel = document.getElementById('details-panel');
button.addEventListener('click', () => {
const expanded = button.getAttribute('aria-expanded') === 'true';
button.setAttribute('aria-expanded', String(!expanded));
panel.hidden = expanded;
button.textContent = expanded ? 'Show details' : 'Hide details';
});
Modal dialog
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-desc">
<h2 id="dialog-title">Confirm deletion</h2>
<p id="dialog-desc">This action cannot be undone. Are you sure you want to delete this item?</p>
<div>
<button>Cancel</button>
<button>Delete</button>
</div>
</div>
Tabs
<div role="tablist" aria-label="Project sections">
<button role="tab" id="tab-overview" aria-selected="true" aria-controls="panel-overview">
Overview
</button>
<button role="tab" id="tab-tasks" aria-selected="false" aria-controls="panel-tasks" tabindex="-1">
Tasks
</button>
</div>
<div role="tabpanel" id="panel-overview" aria-labelledby="tab-overview">
<p>Overview content here.</p>
</div>
<div role="tabpanel" id="panel-tasks" aria-labelledby="tab-tasks" hidden>
<p>Tasks content here.</p>
</div>
Combobox (autocomplete)
<label for="city-input">City</label>
<div>
<input
type="text"
id="city-input"
role="combobox"
aria-expanded="false"
aria-autocomplete="list"
aria-controls="city-listbox"
aria-activedescendant=""
>
<ul role="listbox" id="city-listbox" hidden>
<li role="option" id="opt-nyc">New York</li>
<li role="option" id="opt-la">Los Angeles</li>
<li role="option" id="opt-chi">Chicago</li>
</ul>
</div>
Alert
<!-- Automatically announced by screen readers when content appears -->
<div role="alert">
<p>Error: Your password must be at least 8 characters.</p>
</div>
Testing & Validation
- Inspect the accessibility tree in Chrome DevTools (Elements > Accessibility) or Firefox (Accessibility Inspector) to verify computed roles and names.
- Use the axe browser extension to flag misused ARIA attributes.
- Test with a screen reader to confirm that roles and states are announced correctly during interaction.
- Validate that every
aria-controls,aria-labelledby, andaria-describedbyreference points to an existing element ID.
Best Practices
- Prefer semantic HTML (
<button>,<nav>,<dialog>) over ARIA equivalents; ARIA is for when HTML falls short. - Always pair ARIA roles with the expected keyboard interaction pattern from the WAI-ARIA Authoring Practices Guide.
- Keep ARIA attributes in sync with the visual state—if a panel looks expanded,
aria-expandedmust be"true".
Common Pitfalls
- Adding
role="button"to a<div>without also making it focusable (tabindex="0") and handling Enter/Space key events. - Using
aria-labelon non-interactive, non-landmark elements where screen readers may ignore it (e.g., a plain<div>or<span>).
Anti-Patterns
Over-engineering for hypothetical scale. Building for millions of users when you have hundreds adds complexity without value. Solve today's problems first.
Ignoring the existing ecosystem. Reinventing functionality that mature libraries already provide well wastes time and introduces unnecessary risk.
Premature abstraction. Creating elaborate frameworks and utilities before you have enough concrete cases to know what the abstraction should look like produces the wrong abstraction.
Neglecting error handling at boundaries. Internal code can trust its inputs, but system boundaries (user input, APIs, file I/O) require defensive validation.
Skipping documentation for obvious code. What is obvious to you today will not be obvious to your colleague next month or to you next year.
Install this skill directly: skilldb add accessibility-skills
Related Skills
Accessible Forms
Accessible form design patterns including labels, validation, error handling, and multi-step forms
Axe Testing
Automated accessibility testing with axe-core, including CI integration, custom rules, and result analysis
Color Contrast
Color contrast ratios, visual accessibility, and inclusive design for users with low vision or color blindness
Focus Management
Focus management strategies for single-page applications, modals, route changes, and dynamic content
Keyboard Navigation
Keyboard navigation patterns, focus order, and shortcut design for fully keyboard-accessible interfaces
Screen Reader Compat
Building web content that works correctly with screen readers like NVDA, JAWS, and VoiceOver