← 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

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