Keyboard navigation

If a control cannot be reached and operated with a keyboard alone, it does not exist for a large group of your users — and no automated scanner will tell you.

What goes wrong

Keyboard access breaks in four ways, and almost every finding is one of them.

The control is not reachable. A div with a click handler is not focusable. It looks like a button, behaves like a button for mouse users, and is invisible to the tab sequence. This is the single most common cause, and it arrives with custom component libraries.

The control is reachable but not operable. The element takes focus, but only responds to click. Pressing Enter or Space does nothing. Mouse users never notice.

Focus goes in, and cannot come out. A modal, a date picker, an embedded video or a third-party widget takes focus and holds it. This is a keyboard trap, and it does not end the task — it ends the session, because the only way out is to close the tab.

Focus is invisible. The outline was removed in CSS, usually with outline: none in a reset, and nothing replaced it. The page is fully operable and the user has no idea where they are.

New in WCAG 2.2, there is a fifth that is now extremely common: focus that is visible but obscured by a sticky header or a cookie banner. The indicator is drawn correctly and sits underneath something else.

How to test it

Ten minutes, no tooling.

  1. Put the mouse somewhere you cannot reach.
  2. Load the page and press Tab once. A skip link should appear.
  3. Tab through the entire page. Watch the focus indicator continuously.
  4. At each interactive element, ask: can I see where I am? Does Enter or Space do what it should?
  5. Open every modal, menu and dropdown. Tab inside it. Press Escape. Tab back out.
  6. Complete the primary task — buy the thing, submit the form, book the appointment.

Write down every point where you lost the indicator, could not reach something, could not escape, or could not tell what was focused. That list is a keyboard audit.

How to fix it

Use the native element. This resolves most findings on its own. A <button> is focusable, activates on Enter and Space, exposes the button role, and works with voice control. A <div role="button" tabindex="0"> with a keydown handler is you reimplementing all of that, and the reimplementation is where the bugs are.

<!-- Not reachable, not operable, no role -->
<div class="btn" onclick="submit()">Send</div>

<!-- Reachable, operable, announced correctly -->
<button type="button" onclick="submit()">Send</button>

Never remove the focus indicator without replacing it. If the default ring does not suit the design, draw a better one — but it must meet 3:1 against its background, and it must be visible on every ground the element sits on.

/* The problem */
:focus { outline: none; }

/* A replacement that is actually visible */
:focus-visible {
  outline: 2px solid var(--focus-colour);
  outline-offset: 2px;
}

Manage focus when content appears. When a dialog opens, move focus into it. Keep focus inside while it is open. When it closes, return focus to the control that opened it — otherwise focus falls back to the top of the document and the user restarts the page.

Keep the DOM order and the visual order the same. CSS order, flex-direction: row-reverse and absolute positioning can rearrange what people see without rearranging what they tab through. If the two disagree, the tab sequence jumps around the screen.

Check what your sticky header covers. Add scroll-margin-top to focusable elements, or reduce the sticky area, so focus is never drawn underneath it.

Why it matters commercially

Keyboard barriers are the ones that stop a transaction rather than degrade it. A contrast failure makes your checkout harder to read; a focus trap in the payment modal makes it impossible to complete. In an audit, keyboard findings are disproportionately represented in the critical band for exactly that reason.

Frequently asked questions

How do I test keyboard accessibility?

Put the mouse out of reach and complete your primary task. Tab moves forward, Shift+Tab back, Enter activates links and buttons, Space activates buttons and checkboxes, arrow keys move within a component, and Escape closes. Watch where the focus indicator is at all times. If you lose it, or you cannot get somewhere, or you cannot get back out — that is a finding.

Can a scanner find keyboard problems?

Only the shallowest ones. A scanner can spot a positive tabindex or an element with a click handler and no keyboard handler. It cannot tell you that the focus order jumps to the footer and back, that the modal traps you, or that the focus ring is invisible against the dark section. Those need a person.

Is tabindex the fix?

Almost never. tabindex="0" makes a custom element focusable, which is sometimes right. A positive tabindex is almost always wrong, because it pulls the element out of document order and rearranges the sequence for the whole page. The better fix is usually to use the native element — a button instead of a div — which brings focus, activation and role for free.

Regulatory requirements vary by jurisdiction, service, organisation and other factors. Uxerfy provides accessibility assessments and compliance-oriented information, not legal advice or legal certification. Consult qualified legal counsel for a determination of your obligations.

Check your own site

Prioritised findings, with the evidence and how to fix them.