← ClaudeAtlas

keyboard-interactionlisted

Implement the WAI-ARIA Authoring Practices keyboard contract for the widget you are building — dialog, menu, listbox, combobox, tabs, disclosure, tree, grid. Load before building any custom interactive widget.
soumit-kaz/lazysitter · ★ 1 · Code & Development · score 69
Install: claude install-skill soumit-kaz/lazysitter
# Keyboard interaction patterns ## Name the pattern before writing the widget Users already know these contracts. A "dropdown" that is really a listbox but behaves like a menu is worse than either, because it defeats knowledge the user already has. Decide which of the standard patterns you are implementing, then implement **that** contract. ## The contracts ### Button `Enter` and `Space` activate. That is the whole contract — and it is why `<button>` beats `<div role="button">`, which must re-implement it (and usually forgets `Space`, or forgets that `Space` should activate on keyup and not scroll the page). ### Disclosure (show/hide) `Enter`/`Space` toggles. `aria-expanded` on the trigger, `aria-controls` pointing at the region. No trap, no arrow keys. The simplest pattern and the right answer far more often than a menu. ### Modal dialog `Escape` closes. Focus is trapped inside. `Tab`/`Shift+Tab` cycle within. `role="dialog"` + `aria-modal="true"` + an accessible name via `aria-labelledby`. Content behind is `inert` or `aria-hidden`. Focus returns to the trigger on close. ### Menu / menubar (a list of *actions*) `Enter`/`Space`/`ArrowDown` opens from the trigger. `ArrowUp`/`ArrowDown` move between items (wrapping). `Home`/`End` jump to first/last. Type-ahead jumps to a matching item. `Escape` closes and returns focus. `Tab` closes and moves on. **Roving tabindex**: exactly one item is `tabIndex={0}`, the rest `-1`. Use this for actions. Do **not** use `role="menu"` fo