principlejavascriptCritical
Keyboard navigation — every interactive element must be reachable and operable
Viewed 0 times
WCAG 2.1 Level A
keyboard navigationtabindexfocus managementkeyboard traparia authoring practicesWCAG 2.1.1
Problem
Custom interactive widgets (carousels, dropdowns, date pickers) are mouse-only. Users who rely on keyboards — including people with motor disabilities and power users — cannot operate them.
Solution
Follow established keyboard interaction patterns from the APG (ARIA Authoring Practices Guide). The core rules:
// Keyboard-accessible custom dropdown
function Dropdown({ options }) {
const [open, setOpen] = useState(false);
return (
<div role="combobox" aria-expanded={open}>
<button onClick={() => setOpen(o => !o)} onKeyDown={e => {
if (e.key === 'Escape') setOpen(false);
}}>Select</button>
{open && (
<ul role="listbox">
{options.map(opt => (
<li key={opt} role="option" tabIndex={0}>{opt}</li>
))}
</ul>
)}
</div>
);
}
- All interactive elements must be focusable (tabindex="0" if not natively focusable)
- Tab moves between components; arrow keys move within a composite widget
- Enter/Space activate buttons and checkboxes; Enter follows links
- Escape closes modals, dropdowns, and tooltips
- Home/End jump to first/last item in a list
// Keyboard-accessible custom dropdown
function Dropdown({ options }) {
const [open, setOpen] = useState(false);
return (
<div role="combobox" aria-expanded={open}>
<button onClick={() => setOpen(o => !o)} onKeyDown={e => {
if (e.key === 'Escape') setOpen(false);
}}>Select</button>
{open && (
<ul role="listbox">
{options.map(opt => (
<li key={opt} role="option" tabIndex={0}>{opt}</li>
))}
</ul>
)}
</div>
);
}
Why
WCAG 2.1.1 (Level A) requires all functionality to be operable via keyboard. Motor disabilities, temporary injuries, and power user workflows all depend on keyboard access.
Gotchas
- tabindex values greater than 0 create a custom tab order that is almost always confusing — avoid
- Removing focus outlines (outline:none) without providing an alternative is a WCAG violation
- Focus must not be trapped outside of intentional modal dialogs
- Custom widgets built with divs get zero keyboard behavior automatically — you must implement it entirely
Context
Any custom interactive component: dropdowns, modals, sliders, date pickers, carousels
Revisions (0)
No revisions yet.