| name | aria-apg-patterns |
| description | Accessibility patterns reference based on W3C WAI-ARIA Authoring Practices Guide for implementing accessible web UI components. |
ARIA APG Patterns
Accessibility patterns reference based on W3C WAI-ARIA Authoring Practices Guide
Source: https://www.w3.org/WAI/ARIA/apg/patterns/
This document provides ARIA pattern guidelines for implementing accessible web UI components.
Quick Reference
| Pattern | Use Case | Required Roles |
|---|
| Accordion | Expandable/collapsible sections | button, region |
| Alert | Important message (non-modal) | alert |
| Alert Dialog | Important message (modal) | alertdialog |
| Breadcrumb | Hierarchical navigation | navigation |
| Button | Action trigger | button |
| Carousel | Slide content | region, group |
| Checkbox | Check selection | checkbox |
| Combobox | Autocomplete input | combobox |
| Dialog | Modal dialog | dialog |
| Disclosure | Show/hide content | button |
| Feed | Infinite scroll content | feed, article |
| Grid | Interactive tabular data | grid, row, gridcell |
| Link | Resource reference | link |
| Listbox | Option list selection | listbox, option |
| Menu | Action/function selection | menu, menuitem |
| Menu Button | Menu trigger button | button |
| Meter | Value within range display | meter |
| Radio Group | Single selection | radiogroup, radio |
| Slider | Range value selection | slider |
| Spinbutton | Discrete value input | spinbutton |
| Switch | On/off toggle | switch |
| Table | Static table | table, row, cell |
| Tabs | Tab panel switching | tablist, tab, tabpanel |
| Tooltip | Supplementary info popup | tooltip |
| Tree View | Hierarchical list | tree, treeitem |
Accordion
Vertically stacked set of interactive headings. Each section can be expanded or collapsed.
Keyboard Interaction
| Key | Action |
|---|
Enter / Space | Toggle panel expand/collapse |
Tab | Move to next focusable element |
↓ / ↑ | (Optional) Move focus between headers |
Home / End | (Optional) Move to first/last header |
ARIA Attributes
<h3>
<button aria-expanded="true|false" aria-controls="panel-id">Section Title</button>
</h3>
<div id="panel-id" role="region" aria-labelledby="header-id">Content</div>
Checklist
Alert
Displays important message without interrupting user's current task. Does not move focus.
ARIA Attributes
<div role="alert">Important message content</div>
Checklist
Alert Dialog
Modal dialog that interrupts user to deliver important message.
Keyboard Interaction
| Key | Action |
|---|
Tab | Cycle focus within dialog |
Shift+Tab | Reverse cycle focus |
Escape | Close dialog |
ARIA Attributes
<div role="alertdialog" aria-modal="true" aria-labelledby="title-id" aria-describedby="desc-id">
<h2 id="title-id">Title</h2>
<p id="desc-id">Description</p>
<button>Confirm</button>
</div>
Checklist
Breadcrumb
Displays parent page links of current page in hierarchical order.
ARIA Attributes
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/products/shoes" aria-current="page">Shoes</a></li>
</ol>
</nav>
Checklist
Button
Widget that triggers actions such as form submission, opening dialogs, etc.
Button Types
- Standard Button: Default command button
- Toggle Button: Express pressed/unpressed state with
aria-pressed
- Menu Button: Set
aria-haspopup="menu"
Keyboard Interaction
| Key | Action |
|---|
Enter | Activate button |
Space | Activate button |
ARIA Attributes
<button>Save</button>
<div role="button" tabindex="0" aria-label="Save">Save</div>
<button aria-pressed="false">Mute</button>
<button aria-disabled="true">Submit</button>
Checklist
Carousel
Content presentation that displays slides sequentially.
Keyboard Interaction
| Key | Action |
|---|
Tab | Move between interactive elements in carousel |
| Focus entry | Stop auto-rotation |
ARIA Attributes
<div role="region" aria-roledescription="carousel" aria-label="Featured Products">
<button aria-label="Pause slide rotation">Pause</button>
<button aria-label="Previous slide">Previous</button>
<button aria-label="Next slide">Next</button>
<div aria-live="polite">
<div role="group" aria-roledescription="slide" aria-label="1 of 5">Slide content</div>
</div>
</div>
Checklist
Checkbox
Supports checked/unchecked or partial checked states.
Keyboard Interaction
| Key | Action |
|---|
Space | Toggle check state |
ARIA Attributes
<input type="checkbox" id="agree" />
<label for="agree">I agree</label>
<div role="checkbox" tabindex="0" aria-checked="false" aria-labelledby="label-id"></div>
<span id="label-id">I agree</span>
<div role="checkbox" aria-checked="mixed"></div>
Checklist
Combobox
Input widget with autocomplete functionality.
Keyboard Interaction (Popup Closed)
| Key | Action |
|---|
↓ | Open popup, move to first option |
↑ | Open popup, move to last option |
Escape | Close popup |
Enter | Accept autocomplete suggestion |
Keyboard Interaction (Popup Open)
| Key | Action |
|---|
↓ / ↑ | Move between options |
Enter | Select option, close popup |
Escape | Close popup, return to input |
Home / End | Move to first/last option |
ARIA Attributes
<label for="city">City</label>
<input
type="text"
id="city"
role="combobox"
aria-expanded="false"
aria-controls="city-listbox"
aria-autocomplete="list"
aria-activedescendant="option-1"
/>
<ul id="city-listbox" role="listbox">
<li id="option-1" role="option" aria-selected="true">Seoul</li>
<li id="option-2" role="option">Busan</li>
</ul>
Checklist
Dialog (Modal)
Modal window overlaid on main window. Interaction with content outside dialog is blocked.
Keyboard Interaction
| Key | Action |
|---|
Tab | Cycle focus within dialog (last→first) |
Shift+Tab | Reverse cycle (first→last) |
Escape | Close dialog |
Initial Focus Placement Rules
- Structured content (lists, tables): Add
tabindex="-1" to start point
- Large content: Focus on title or first paragraph
- Destructive actions (delete, etc.): Focus on safest button (Cancel)
ARIA Attributes
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title" aria-describedby="dialog-desc">
<h2 id="dialog-title">Delete File</h2>
<p id="dialog-desc">Are you sure you want to delete this file?</p>
<button>Delete</button>
<button>Cancel</button>
</div>
Checklist
Disclosure
Widget that collapses or expands content.
Keyboard Interaction
| Key | Action |
|---|
Enter | Toggle content show/hide |
Space | Toggle content show/hide |
ARIA Attributes
<button aria-expanded="false" aria-controls="content-id">Show more</button>
<div id="content-id" hidden>Hidden content</div>
Checklist
Feed
Section that automatically loads new content as user scrolls.
Keyboard Interaction
| Key | Action |
|---|
Page Down | Move focus to next article |
Page Up | Move focus to previous article |
Ctrl+End | Move to element after feed |
Ctrl+Home | Move to element before feed |
ARIA Attributes
<div role="feed" aria-labelledby="feed-title" aria-busy="false">
<h2 id="feed-title">Latest News</h2>
<article aria-posinset="1" aria-setsize="-1" aria-labelledby="article-1-title" aria-describedby="article-1-content">
<h3 id="article-1-title">Article Title</h3>
<p id="article-1-content">Article content</p>
</article>
</div>
Checklist
Grid
Interactive tabular data navigable with arrow keys.
Keyboard Interaction
| Key | Action |
|---|
→ / ← / ↑ / ↓ | Move focus between cells |
Home / End | Move to first/last cell in row |
Ctrl+Home / Ctrl+End | Move to first/last cell in grid |
Page Up / Page Down | Scroll by row |
Enter / F2 | Enter cell edit mode |
Escape | Restore grid navigation |
ARIA Attributes
<div role="grid" aria-labelledby="grid-title">
<div role="row">
<div role="columnheader">Name</div>
<div role="columnheader">Age</div>
</div>
<div role="row">
<div role="gridcell" tabindex="0">John Doe</div>
<div role="gridcell">30</div>
</div>
</div>
Checklist
Link
Interactive reference to a resource.
Keyboard Interaction
| Key | Action |
|---|
Enter | Execute link |
ARIA Attributes
<a href="/page">Go to page</a>
<span role="link" tabindex="0" onclick="navigate()" onkeydown="handleKeyDown(event)"> Go to page </span>
Checklist
Listbox
List where user can select one or more options.
Keyboard Interaction (Single Select)
| Key | Action |
|---|
↓ / ↑ | Move focus |
Home / End | Move to first/last option |
| Type character | Search for item starting with that character |
Keyboard Interaction (Multi Select)
| Key | Action |
|---|
Space | Toggle focused option selection |
Shift+↓ / Shift+↑ | Move focus + toggle selection |
Ctrl+A | Select/deselect all |
ARIA Attributes
<div role="listbox" aria-labelledby="label-id" aria-multiselectable="true">
<div role="option" aria-selected="true">Option 1</div>
<div role="option" aria-selected="false">Option 2</div>
</div>
Checklist
Menu and Menubar
Widget offering list of actions or functions.
Keyboard Interaction
| Key | Action |
|---|
Enter / Space | Activate item |
↓ / ↑ | Move in vertical menu |
→ / ← | Move in horizontal menubar / Open/close submenu |
Escape | Close menu |
Home / End | Move to first/last item |
| Type character | Move to matching label item |
ARIA Attributes
<div role="menubar" aria-label="Edit">
<div role="menuitem" aria-haspopup="menu" aria-expanded="false">
File
<div role="menu">
<div role="menuitem">New File</div>
<div role="menuitem">Open</div>
<div role="menuitemcheckbox" aria-checked="true">Auto Save</div>
</div>
</div>
</div>
Checklist
Menu Button
Button that opens a menu.
Keyboard Interaction
| Key | Action |
|---|
Enter / Space | Open menu, focus first item |
↓ | (Optional) Open menu, focus first item |
↑ | (Optional) Open menu, focus last item |
ARIA Attributes
<button aria-haspopup="menu" aria-expanded="false" aria-controls="menu-id">Options</button>
<div id="menu-id" role="menu">
<div role="menuitem">Item 1</div>
<div role="menuitem">Item 2</div>
</div>
Checklist
Meter
Graphical display of numeric value within a defined range.
Warning: Use progressbar role for progress indication
ARIA Attributes
<div role="meter" aria-valuenow="75" aria-valuemin="0" aria-valuemax="100" aria-label="Battery level">75%</div>
<div
role="meter"
aria-valuenow="50"
aria-valuemin="0"
aria-valuemax="100"
aria-valuetext="50% (6 hours) remaining"
aria-label="Battery"
></div>
Checklist
Radio Group
Set of radio buttons where only one can be selected at a time.
Keyboard Interaction
| Key | Action |
|---|
Tab | Enter group (selected button or first button) |
Space | Select current focused button |
→ / ↓ | Move to next button + select (cycles) |
← / ↑ | Move to previous button + select (cycles) |
ARIA Attributes
<div role="radiogroup" aria-labelledby="group-label">
<span id="group-label">Shipping Method</span>
<div role="radio" aria-checked="true" tabindex="0">Standard Shipping</div>
<div role="radio" aria-checked="false" tabindex="-1">Express Shipping</div>
</div>
Checklist
Slider
Input widget for selecting value within a given range.
Keyboard Interaction
| Key | Action |
|---|
→ / ↑ | Increase value |
← / ↓ | Decrease value |
Home | Set to minimum |
End | Set to maximum |
Page Up | (Optional) Increase by large step |
Page Down | (Optional) Decrease by large step |
ARIA Attributes
<div role="slider" tabindex="0" aria-valuenow="50" aria-valuemin="0" aria-valuemax="100" aria-label="Volume"></div>
<div
role="slider"
aria-valuenow="1"
aria-valuemin="0"
aria-valuemax="6"
aria-valuetext="Monday"
aria-label="Day selection"
></div>
Checklist
Spinbutton
Input widget for selecting value from discrete value range.
Keyboard Interaction
| Key | Action |
|---|
↑ | Increase value |
↓ | Decrease value |
Home | Set to minimum |
End | Set to maximum |
Page Up | (Optional) Increase by large step |
Page Down | (Optional) Decrease by large step |
ARIA Attributes
<div role="spinbutton" tabindex="0" aria-valuenow="5" aria-valuemin="0" aria-valuemax="59" aria-label="Minutes">
<button aria-label="Increase">+</button>
<span>05</span>
<button aria-label="Decrease">-</button>
</div>
Checklist
Switch
Widget for selecting between on/off states.
Keyboard Interaction
| Key | Action |
|---|
Space | Toggle state |
Enter | (Optional) Toggle state |
ARIA Attributes
<button role="switch" aria-checked="false">Notifications</button>
<input type="checkbox" role="switch" aria-checked="true" />
Checklist
Table
Static table structure (no interactive features).
For interactive tables, use Grid pattern
ARIA Attributes
<table role="table" aria-labelledby="table-title">
<caption id="table-title">
User List
</caption>
<thead>
<tr role="row">
<th role="columnheader" aria-sort="ascending">Name</th>
<th role="columnheader">Email</th>
</tr>
</thead>
<tbody>
<tr role="row">
<td role="cell">John Doe</td>
<td role="cell">john@example.com</td>
</tr>
</tbody>
</table>
Checklist
Tabs
Layered content sections displaying one panel at a time.
Keyboard Interaction
| Key | Action |
|---|
Tab | Enter tab list (active tab) |
→ / ← | Move to next/previous tab (cycles) |
Space / Enter | (Manual activation) Activate tab |
Home / End | Move to first/last tab |
Delete | (Optional) Delete tab |
ARIA Attributes
<div role="tablist" aria-label="Content tabs">
<button role="tab" aria-selected="true" aria-controls="panel-1" tabindex="0">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" tabindex="-1">Tab 2</button>
</div>
<div id="panel-1" role="tabpanel" aria-labelledby="tab-1" tabindex="0">Panel 1 content</div>
<div id="panel-2" role="tabpanel" aria-labelledby="tab-2" hidden>Panel 2 content</div>
Checklist
Tooltip
Popup displaying information when element receives focus or hover.
Warning: This pattern is currently under W3C development
Keyboard Interaction
| Key | Action |
|---|
Escape | Close tooltip |
ARIA Attributes
<button aria-describedby="tooltip-1">Save</button>
<div id="tooltip-1" role="tooltip">Save your changes (Ctrl+S)</div>
Checklist
Tree View
Widget presenting hierarchical list.
Keyboard Interaction
| Key | Action |
|---|
Enter | Activate node (default action) |
→ | Open closed node / Move to child |
← | Close open node / Move to parent |
↓ / ↑ | Move to next/previous focusable node |
Home / End | Move to first/last node |
| Type character | Move to node starting with that character |
Keyboard Interaction (Multi Select)
| Key | Action |
|---|
Space | Toggle focused node selection |
Shift+↓ / Shift+↑ | Toggle selection while moving |
Ctrl+A | Select/deselect all |
ARIA Attributes
<ul role="tree" aria-labelledby="tree-label" aria-multiselectable="false">
<li role="treeitem" aria-expanded="true" aria-selected="false">
Folder 1
<ul role="group">
<li role="treeitem" aria-selected="true">File 1</li>
<li role="treeitem" aria-selected="false">File 2</li>
</ul>
</li>
</ul>
Checklist
Common Patterns
Focus Management
function trapFocus(element: HTMLElement) {
const focusableElements = element.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const first = focusableElements[0] as HTMLElement;
const last = focusableElements[focusableElements.length - 1] as HTMLElement;
element.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
}
Roving Tabindex
Used in tab lists, radio groups, etc.:
function setRovingTabindex(container: HTMLElement, activeSelector: string) {
const items = container.querySelectorAll('[role="tab"], [role="radio"]');
items.forEach((item) => {
(item as HTMLElement).tabIndex = item.matches(activeSelector) ? 0 : -1;
});
}
Live Regions
Announce dynamic content changes:
<div aria-live="assertive" aria-atomic="true">Error: This field is required.</div>
<div aria-live="polite">3 search results found</div>
References