# ARIA Patterns & Keyboard Interaction Reference ## Landmark Roles Every page should have these landmarks: ```html
``` **Semantic HTML equivalents:** `
`, `
`, `
`, `
`, `
` provide implicit roles — no need to double up with explicit `role` attributes. ## Live Regions ### When to Use | Pattern | Attribute | Use Case | |---------|-----------|----------| | Polite | `aria-live="polite"` | Toast notifications, status updates, search result counts | | Assertive | `aria-live="assertive"` | Error messages, urgent alerts, form validation errors | | Status | `role="status"` | Loading indicators, progress updates | | Alert | `role="alert"` | Error dialogs, time-sensitive warnings | | Log | `role="log"` | Chat messages, activity feeds | | Timer | `role="timer"` | Countdown timers | ### Implementation ```html

Please enter a valid email address.

Loading results...
``` **Key rule:** The live region container must exist in the DOM *before* content is injected. Adding `aria-live` to a newly created element won't announce it. ## Focus Management ### Focus Trap (Modals) ```javascript // Trap focus inside modal const modal = document.querySelector('[role="dialog"]'); const focusable = modal.querySelectorAll( 'a[href], button, textarea, input, select, [tabindex]:not([tabindex="-1"])' ); const first = focusable[0]; const last = focusable[focusable.length - 1]; modal.addEventListener('keydown', (e) => { if (e.key === 'Tab') { if (e.shiftKey && document.activeElement === first) { e.preventDefault(); last.focus(); } else if (!e.shiftKey && document.activeElement === last) { e.preventDefault(); first.focus(); } } if (e.key === 'Escape') closeModal(); }); ``` ### Focus Restoration ```javascript // Save focus before opening modal const trigger = document.activeElement; openModal(); // Restore focus on close function closeModal() { modal.hidden = true; trigger.focus(); } ``` ### Skip Link ```html Skip to main content
``` ```css .skip-link { position: absolute; left: -9999px; z-index: 999; } .skip-link:focus { left: 10px; top: 10px; background: #000; color: #fff; padding: 8px 16px; } ``` ## Keyboard Interaction Patterns ### Tabs ``` Tab → Move to tab list, then to tab panel Arrow Left/Right → Switch between tabs Home → First tab End → Last tab ``` ```html
...
...
``` ### Combobox / Autocomplete ``` Arrow Down → Open list / next option Arrow Up → Previous option Enter → Select option Escape → Close list Type → Filter options ``` ### Menu ``` Enter/Space → Activate item Arrow Down → Next item Arrow Up → Previous item Arrow Right → Open submenu Arrow Left → Close submenu Escape → Close menu ``` ### Accordion ``` Enter/Space → Toggle section Arrow Down → Next header Arrow Up → Previous header Home → First header End → Last header ``` ## Framework-Specific ARIA ### React ```jsx // Announce route changes (SPA)
{`Navigated to ${pageTitle}`}
// Error boundary with accessible error

Something went wrong

{error.message}

``` ### Vue ```vue

{{ results.length }} results found

``` ### Angular ```html

Confirm Action

``` ## Common ARIA Mistakes | Mistake | Why It's Wrong | Fix | |---------|---------------|-----| | `
` without keyboard | Div doesn't get keyboard events | Use `