← All criteria

Operable · Level A · 2.1.1

Keyboard

Everything that can be done with a mouse has to be doable with just a keyboard too, and without requiring exact timing between keystrokes.

  • Blind
  • Low vision
  • Motor
The problem, in practice — select the image to enlarge it
An e-commerce product page comparing keyboard accessibility. 'Not accessible with keyboard' shows an image carousel, a 'Play video' button, an 'Open map' button, and a 'More info' dropdown that only respond to mouse clicks or mouse hover, so a keyboard user can't reach or activate any of them. 'Fully accessible with keyboard' shows the same carousel, video, map, and dropdown all reachable with Tab and operable with Enter or Space, with arrow keys advancing the carousel and Escape closing menus — so everything available with a mouse is also available using only a keyboard, without needing precise timing between keystrokes.

How to recognize it

Put the mouse away and try to complete the same task using only Tab, Shift+Tab, Enter, Space, and the arrow keys. Custom controls (the same <div>-instead-of-<button> pattern from 4.1.2) are the usual cause: if it has no tabindex, Tab skips right over it and you can never reach it at all. A menu, tab strip, or dropdown that opens on mouse click but does nothing when you press Enter or Space on it is failing. Drag-and-drop interactions — reordering a list, moving a card between columns — fail if dragging is the only way to do it, since there's no keyboard equivalent for a mouse drag. That's a real failure, not the criterion's narrow exception: the exception only covers input where the path of movement itself matters (freehand drawing, signing your name) — reordering a list only cares about the start and end position, so a keyboard alternative is required and possible.

How to fix it

Reach for the native element first — <button>, <a>, <select>, <input> — and keyboard support comes for free. When a custom widget is unavoidable, give it tabindex="0" so Tab can reach it, and add a keydown handler that responds to Enter and/or Space the same way the click handler does; for composite widgets like tabs or menus, arrow keys are the expected pattern instead. You don't have to match a specific platform's exact key convention — WCAG only requires that the interface be operable by keyboard, not that it use one particular key for one particular action. For drag-and-drop, don't try to make the drag itself keyboard-operable — add a separate keyboard-usable equivalent instead, like 'move up' / 'move down' buttons next to each item.

Example

Avoid

<div class="menu-toggle" onclick="toggleMenu()">Menu</div>
<div class="tab" onclick="selectTab(2)">Settings</div>
<li draggable="true" ondragstart="handleDrag(event)">Item</li>

Prefer

<button onclick="toggleMenu()">Menu</button>
<div class="tab" role="tab" tabindex="0" onclick="selectTab(2)" onkeydown="if(['Enter',' '].includes(event.key)) selectTab(2)">Settings</div>
<li draggable="true" ondragstart="handleDrag(event)">Item <button aria-label="Move item up">↑</button> <button aria-label="Move item down">↓</button></li>

Resources