Keyboard Navigation
Not everyone uses a mouse. People with motor disabilities, users of screen readers, and many power users navigate entirely with a keyboard. WCAG Principle 2 (Operable) dedicates a full guideline, Guideline 2.1, to ensuring all functionality is available by keyboard.
The good news: if you build with semantic HTML, a great deal of keyboard accessibility comes for free. The problems almost always arise from custom interactive components, CSS that obscures focus, or JavaScript that intercepts key events unexpectedly.
How Keyboard Navigation Works
The default keyboard navigation model is simple:
- Tab moves focus forward through interactive elements
- Shift + Tab moves focus backward
- Enter activates links and buttons
- Space activates buttons (and scrolls the page when nothing is focused)
- Arrow keys move within widgets like radio groups, menus, and listboxes
- Escape closes modals, tooltips, and dropdowns
Native HTML elements handle all of this automatically. A <button>
responds to Tab, Enter, and Space without any JavaScript. A custom
<div role="button"> requires you to write all of those
keyboard handlers yourself.
SC 2.1.1: Keyboard (Level A)
All functionality must be operable through a keyboard interface. The only exception is functionality that requires path-dependent input, a freehand drawing tool, for instance, where the path itself is the input.
"All functionality" means everything: opening menus, submitting forms, activating dialogs, playing and pausing media, sorting tables, uploading files. If a mouse user can do it, a keyboard user must be able to do it too.
Common causes of failure:
-
Custom interactive controls built from
<div>or<span>with only click handlers, keyboard users can't reach or activate them. - Dropdown menus that appear on hover but can't be reached by Tab or opened by Enter/Space.
- Drag-only functionality, sliders, sortable lists, with no keyboard or single-pointer alternative.
SC 2.1.2: No Keyboard Trap (Level A)
If focus can move into a component, it must be possible to move focus out of that component using only the keyboard. If non-standard keys are required to escape, the user must be informed.
A keyboard trap is one of the most disabling failures possible. A user who tabs into a component and cannot escape it is effectively locked out of the rest of the page.
The modal exception: Modal dialogs intentionally trap focus within the dialog while it is open. This is correct behavior, focus should not be allowed to wander behind the modal. However, pressing Escape must close the modal and return focus to the element that opened it. The trap is acceptable; the inability to escape is not.
SC 2.4.7: Focus Visible (Level AA)
Keyboard-operable interfaces must have a visible focus indicator. When you tab through a page, you should always be able to see where focus is.
The most common way to break this: outline: none or
outline: 0 in CSS, applied globally or to interactive elements.
This removes the browser's default focus ring without providing a replacement.
The result is that keyboard users cannot tell where they are on the page.
/* Never do this without a replacement */
* { outline: none; }
a:focus { outline: none; }
button:focus { outline: none; }
/* Instead, provide your own visible focus style */
a:focus,
button:focus {
outline: 3px solid #0000bb;
outline-offset: 2px;
}
WCAG 2.2 adds SC 2.4.11 (Focus Not Obscured, Level AA), which requires that a focused element not be entirely hidden behind a sticky header, cookie banner, or other persistent overlay. If your sticky nav covers focused elements, this is now a WCAG 2.2 AA failure.
SC 2.4.3: Focus Order (Level A)
When navigating sequentially, focus must move in an order that preserves meaning and operation. In most cases, the natural DOM order, top to bottom, left to right, is the correct focus order.
Problems arise when CSS reorders elements visually without matching the DOM order.
A sidebar that appears first visually (via CSS order: -1 or
absolute positioning) but appears last in the DOM will receive focus last,
which may be confusing or nonfunctional.
Avoid tabindex values greater than 0. Positive tabindex
values override the natural tab order and are nearly impossible to maintain
correctly as a page grows. tabindex="0" (to add an element
to the tab order at its natural position) and tabindex="-1"
(to make an element programmatically focusable but not part of the tab order)
are both acceptable.
Testing Keyboard Accessibility
Put the mouse away. Literally. Unplug it or push it aside. Then:
-
Press Tab and make sure you can see where focus is at all times.
If focus ever becomes invisible, you've found a
outline: noneproblem. - Tab through every interactive element on the page. Verify you can reach everything a mouse user can reach.
- Activate links with Enter and buttons with both Enter and Space. Custom components sometimes handle one but not the other.
- Open any dropdowns, modals, or dialogs. Make sure you can move focus into them, operate them, and return focus to where you started.
- Press Escape inside any overlay or popup. It should close.
- Check that Tab eventually returns you to the browser's address bar: there must be no keyboard traps.
This manual test takes about ten minutes on a typical page and will find problems that no automated tool can catch.
Common Failures
- Custom components with click handlers only
-
A
<div>withonclickand notabindex, role, or keyboard event handlers. It works with a mouse. It's invisible to keyboard users and screen readers. - Removed focus styles
-
outline: noneapplied globally, often in a CSS reset or "normalize" stylesheet, without a replacement. One line of CSS locks out all keyboard users simultaneously. - Focus hidden behind sticky headers
- A fixed navigation bar at the top of the page that overlaps focused elements as users scroll. The element is focused, but the visual indicator is hidden behind the nav. A WCAG 2.2 AA failure under SC 2.4.11.
- Hover-only interactions
- Dropdown menus, tooltips, or actions that appear only on mouse hover and are never reachable by keyboard. If it requires a mouse to see it, keyboard users will never find it.
- Modal dialogs that don't trap focus
- A dialog that opens but allows focus to wander behind it, so keyboard users can interact with content that's visually hidden behind the overlay. Focus must be constrained within an open modal.
- Positive tabindex values
-
tabindex="3",tabindex="10"and similar positive values pull elements out of natural tab order and into an alternate sequence that quickly becomes unpredictable and incorrect as pages are updated.