What this Level A criterion requires
Every page function — opening a menu, picking a date, dragging a slider, completing a captcha — must be operable from the keyboard alone. The user must be able to reach the control via Tab, activate it via Enter or Space (or arrow keys for composites), and not be required to time keystrokes (no “press exactly 3 times in 0.5 seconds”).
The companion criterion 2.1.2 No Keyboard Trap (Level A) requires that focus, once entered, can also leave by keyboard. 2.1.4 Character Key Shortcuts (Level A) regulates single-key shortcuts.
Why keyboard parity matters
About 7% of users on desktop and laptop devices rely primarily on keyboard input (WebAIM Screen Reader User Survey #10, 2024). The population includes screen-reader users, switch users, voice- control users, motor-impaired users, and short-term-injury users. A site that loses keyboard parity is unusable for that 7% — and fragile for the other 93% during any moment of pointer unavailability (touchpad failure, sticky mouse button, full-hand typing).
What “operable” means in detail
For each function, three things must work:
- Reach. Tab order leads to the control or a way to activate it. Skip-link patterns get past long navigations.
- Activate. Enter on links and submit-buttons; Space on non-submit buttons and toggles; arrow keys to navigate within a composite (radio group, listbox, menu, tablist).
- Exit. Escape (or Tab out) closes a popup or dismisses a modal. No keyboard trap.
The activation keys are conventional — defined per role in the WAI-ARIA Authoring Practices Guide. A custom widget that ignores these conventions surprises users even when the criterion technically passes.
Common failure modes
<div>button. Click handler attached, notabindex, no keyboard handler. The control is not reachable and not activatable. Use<button>.- Hover-only menu. Drop-down opens on
mouseenter, never on focus. Add a focus listener; or, better, use a real<button>- popover pattern.
- Drag-only sortable. No keyboard alternative for reordering. Add Move-up / Move-down buttons (see /wcag/2.2/aa/2.5.7).
- Keyboard trap inside iframe. Focus enters an embedded video
player and cannot leave by Tab. The host must provide an exit
affordance or use
aria-modalcorrectly. - Image-zoom requires pinch. Keyboard
+/-or arrow-key pan equivalents required. - Custom autocomplete with click-only selection. Add Up/Down to traverse, Enter to select, Escape to dismiss (/aria/combobox).
What is not required
- The keyboard interaction does not have to be identical to the pointer interaction. A drag can be replaced by a button-based reorder.
- The criterion does not regulate the quality of the keyboard interaction (efficiency, ergonomics) — only that it exists. WCAG 2.1.4 Character Key Shortcuts addresses single-key shortcuts; WCAG 2.4.3 Focus Order addresses meaningful ordering.
Authoring patterns
Focus management on open/close
When opening a menu or modal, move focus into the new region. When closing, return focus to the trigger.
function openMenu(trigger, menu) {
menu.hidden = false;
menu.querySelector('[role="menuitem"]')?.focus();
}
function closeMenu(trigger, menu) {
menu.hidden = true;
trigger.focus();
}
The native <dialog> element automates this; custom widgets must
do the bookkeeping.
Focus trap inside a modal
modal.addEventListener('keydown', (e) => {
if (e.key !== 'Tab') return;
const focusable = [...modal.querySelectorAll(FOCUSABLE_SEL)];
const first = focusable[0], last = focusable.at(-1);
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
});
<dialog>.showModal() handles the trap automatically across
Chromium, WebKit, and Gecko since 2022.
Composite widget arrow keys
For tablist, listbox, menu, and tree roles, Tab moves into and out of the widget; arrow keys move within. The APG keyboard interaction tables list the exact bindings per role.
Verification
- Unplug the mouse.
- Press Tab on the home page; can you reach every control?
- Activate every control with Enter / Space / arrows as appropriate.
- Open every popup; close with Escape; verify focus returns to the trigger.
- Confirm
:focus-visibleshows on every focused element (/wcag/2.2/aa/2.4.7).
About 30% of 2.1.1 violations are detectable by automated tools
(missing tabindex on interactive controls); the rest require
manual keyboard walkthrough.
Cross-engine support
Native HTML elements are keyboard-accessible by default in
Chromium (Blink), WebKit, and Gecko. Differences arise in custom
patterns: WebKit on macOS requires the system “Full Keyboard
Access” preference for <button> to receive Tab focus; Safari 13+
respects the standard behaviour by default since 2020.
Further reading
- WCAG 2.2 §2.1.1 Keyboard.
- WAI-ARIA Authoring Practices, Keyboard Interaction.
- WebAIM Keyboard Accessibility has the densest single-page set of patterns and failures.
- The Inclusive Components book by Heydon Pickering walks 10 widget patterns end-to-end.