// guide

Keyboard Accessibility Testing: A Developer's Walkthrough

A hands-on guide to testing your web interfaces with a keyboard. Covers the keys you need, a repeatable testing procedure, the most common failures developers introduce, and how to debug focus order issues.

beginner testing

// 01 · why keyboard testing matters

Why Keyboard Testing Matters

Keyboard accessibility is not just about screen reader users. A wide range of people rely on the keyboard as their primary or only way to interact with a web page:

  • People with motor disabilities who cannot use a mouse or trackpad due to limited fine motor control, tremors, or paralysis.
  • Power users who prefer keyboard shortcuts for speed and efficiency, and who expect standard keyboard conventions to work.
  • Voice control users whose software (Dragon NaturallySpeaking, Voice Control on macOS, Voice Access on Android) translates voice commands into keyboard events. If your component does not respond to keyboard events, voice control cannot operate it.
  • Switch device users who use adaptive hardware like sip-and-puff devices, single-button switches, or head-tracking systems. These devices generate keyboard events, not mouse events.
  • People with temporary injuries such as a broken arm, RSI, or post-surgical limitations that make a mouse painful or impossible to use.

If any interactive element on your page cannot be reached, operated, and exited with a keyboard alone, you are blocking all of these users. This is not an edge case. WCAG 2.1 Level A criterion 2.1.1 (Keyboard) requires that all functionality be operable through a keyboard interface. Many accessibility laws worldwide reference this criterion directly.

Keyboard testing is the highest-value accessibility test you can run A five-minute keyboard walkthrough of your page will uncover more real accessibility barriers than most automated scanning tools. Automated tools catch about 30% of WCAG issues. Keyboard testing catches interaction failures that no scanner can detect.

// 02 · the essential keys

The Essential Keys

You only need a handful of keys to test keyboard accessibility. These are the keys that assistive technologies and keyboard-only users rely on to navigate and operate web interfaces.

Key Action
Tab / Shift + Tab Move forward and backward between interactive elements (links, buttons, form controls). This is the primary navigation mechanism for keyboard users.
Enter Activate links and buttons. This is the keyboard equivalent of clicking.
Space Activate buttons, toggle checkboxes and switches, scroll the page. Note that Space activates buttons but does not follow links (unlike Enter).
Escape Close modals, dismiss menus, collapse tooltips. The universal "get me out of here" key for any overlay or temporary UI.
Arrow keys Navigate within composite widgets: cycle through tabs in a tablist, move between items in a menu, select radio buttons in a radio group, traverse options in a combobox.
Home / End Jump to the first or last item in a list, menu, or tablist. Not required for all components, but expected in menus and tab interfaces.
Tab vs. Arrow keys A common source of confusion: Tab moves between widgets (from a button to a text field to a tab list), while Arrow keys move within a widget (between tabs in a tab list, between items in a menu). This distinction is called the "roving tabindex" or "composite widget" pattern and is critical to get right.

// 03 · how to run a keyboard test

How to Run a Keyboard Test

Follow this procedure every time you build or modify an interactive component. It takes less than five minutes and catches the most common accessibility failures.

  1. Put away your mouse. Unplug it or move it out of reach. If you touch it during testing, you are no longer testing keyboard accessibility. Trackpad gestures count as mouse input.
  2. Start at the browser address bar. Click the address bar and press Tab to begin navigating into the page. This simulates a keyboard user arriving on the page for the first time.
  3. Tab through the entire page. Press Tab repeatedly to move through every interactive element. Note the order in which elements receive focus. Does the order make logical sense? Does it follow the visual layout?
  4. Check that every interactive element receives visible focus. As you tab, each focused element should have a clearly visible focus indicator (outline, ring, or highlight). If focus seems to disappear, an element has had its focus indicator removed.
  5. Verify all functionality works. Activate every button with Enter or Space. Follow every link with Enter. Open menus, toggle switches, expand accordions, submit forms. Everything you can do with a mouse must also work with the keyboard.
  6. Check for keyboard traps. At every point during your test, can you Tab away from the current element? If pressing Tab repeatedly keeps you stuck inside a component with no way to leave, that is a keyboard trap. The only acceptable keyboard trap is a modal dialog, which should trap focus intentionally and release it on Escape.
  7. Test Escape on any overlays. Open every modal, menu, tooltip, and popover. Press Escape. It should close immediately.
  8. Verify focus returns to the trigger after closing overlays. When you close a modal, menu, or popover with Escape, focus should return to the element that opened it (the trigger button). If focus moves to the top of the page or to some unrelated element, the user loses their place.
macOS users: enable full keyboard access By default, macOS only allows Tab to focus text fields and lists, not buttons or links. Go to System Settings > Keyboard and enable "Keyboard navigation" (or press Ctrl + F7 in older versions) to allow Tab to reach all interactive controls. Without this setting, your keyboard tests will give false results.

// 04 · common failures and fixes

Common Failures and Fixes

These are the keyboard accessibility failures developers introduce most frequently. Each one breaks the experience for every keyboard user, and each one has a straightforward fix.

Using <div onclick> instead of <button> A <div> with a click handler is not keyboard accessible. It does not appear in the tab order, it does not respond to Enter or Space, and screen readers do not announce it as an interactive element. Adding tabindex="0" and a keydown handler is a fragile workaround that still lacks the correct role and states.

Fix: Use a native <button> element. It is focusable, activatable with Enter and Space, and announced as a button by screen readers — all with zero JavaScript. If you need it to look like a link, style it with CSS.
Missing focus indicators Adding :focus { outline: none; } or outline: 0; in a CSS reset removes the browser's default focus ring without replacing it. Keyboard users can no longer see where they are on the page. This is one of the most common and most damaging accessibility failures on the web.

Fix: Use :focus-visible to show a focus indicator only when the user is navigating with a keyboard. Provide a visible outline with at least 3:1 contrast against the background. Example: :focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
Keyboard traps Focus enters a component (a carousel, video player, embedded widget, or rich text editor) and cannot leave. Pressing Tab cycles through the component's internal elements endlessly. The user is stuck with no way to reach the rest of the page.

Fix: Ensure focus can always leave a component by pressing Tab. If the component is a modal dialog, trap focus intentionally but always provide Escape to close and return focus to the trigger. For embedded widgets, test that Tab eventually exits the widget.
Incorrect tab order with positive tabindex Using tabindex="1", tabindex="5", or any positive value forces an element to the front of the tab order, overriding the natural DOM sequence. This creates a confusing, unpredictable focus order that is nearly impossible to maintain as the page grows.

Fix: Never use positive tabindex values. Use only tabindex="0" (to add an element to the natural tab order) or tabindex="-1" (to make an element programmatically focusable without adding it to the tab order). Control focus order through DOM order instead.
Missing skip link Without a skip link, keyboard users must Tab through the entire site header, navigation, and logo on every single page load before reaching the main content. On sites with complex navigation, this can mean dozens of tab stops before the user reaches what they came for.

Fix: Add a skip link as the very first focusable element on the page. It should be visually hidden until focused and jump focus to the main content area. See the Skip Links pattern for a complete implementation.

// 05 · focus order debugging

Focus Order Debugging

Focus order is the sequence in which elements receive focus when a user presses Tab. By default, this follows the DOM order — the order elements appear in your HTML source. Visual layout does not determine focus order unless you take steps to align them.

DOM Order vs. Visual Order

CSS properties that rearrange visual layout without changing DOM order are a frequent source of focus order bugs:

  • flexbox order — Using order: -1 or order: 2 changes where an element appears visually but not where it sits in the tab order. A button that appears first on screen might be last in the tab order.
  • grid placement — Grid areas, grid-row, and grid-column can place elements anywhere in the visual grid while the DOM order remains unchanged. Users tabbing through the page will follow the source order, not the grid layout.
  • position: absolute — Absolutely positioned elements stay in their DOM position for tab order, even if they appear elsewhere visually.
WCAG 2.4.3 Focus Order If the visual order of interactive elements is meaningful, the focus order must match it. When you rearrange elements visually with CSS, you risk creating a disconnect between what the user sees and where focus actually moves. The fix is almost always to change the DOM order to match the intended visual order, rather than relying on CSS reordering.

tabindex Pitfalls

  • tabindex="0" — Adds an element to the natural tab order at its DOM position. Use this for custom interactive elements that are not natively focusable (e.g., a <div> with role="button"). But first, ask whether you should use a native element instead.
  • tabindex="-1" — Removes an element from the tab order but keeps it programmatically focusable via element.focus() in JavaScript. Use this for elements that should receive focus only through scripted focus management (e.g., the heading of a section after a skip link jump, or the first item in a menu on open).
  • Positive tabindex values — Never use them. A tabindex="1" element will receive focus before every tabindex="0" element on the page, regardless of DOM position. Multiple positive values create competing priorities that are nearly impossible to reason about.

Using Browser DevTools

Modern browsers include accessibility inspectors that can help you visualize and debug focus order:

  • Chrome DevTools — Open DevTools, go to the "Elements" panel, and enable the Accessibility pane. The "Accessibility Tree" view shows you how the page is presented to assistive technology. You can also use the "Rendering" tab and check "Show accessibility tree" to see the full tree overlay.
  • Firefox DevTools — Open DevTools and switch to the "Accessibility" tab. It shows the accessibility tree, highlights focusable elements, and can run automated checks for tab order issues. The "Tab order" checkbox in the Accessibility panel overlays numbered badges on each focusable element in tab order.
  • Safari Web Inspector — Open Web Inspector, go to the "Elements" tab, and select the "Node" sidebar. The "Accessibility" section shows the role, label, and focusability of the selected element.
Quick focus order audit Open your browser console and paste: document.querySelectorAll('[tabindex]') to find every element with an explicit tabindex. If you see any positive values, they need to be removed. Then tab through the page manually and compare the focus sequence to the visual layout.

// 06 · pattern references

Pattern References

The table below maps common keyboard behaviors to A11yPath patterns that demonstrate them. Each pattern includes a working implementation with the correct keyboard interactions built in.

Pattern Key Keyboard Behavior
Skip Links Tab to first element reveals skip link, Enter jumps to main content
Modal Dialog Escape to close, focus trap keeps Tab inside dialog, focus returns to trigger on close
Tabs Arrow keys to switch between tabs, Tab moves into the panel
Dropdown Menu Arrow keys to navigate menu items, Escape to close, focus returns to trigger
Accordion Enter or Space to toggle sections open and closed
Accessible Forms Tab through fields, Space for checkboxes, Enter to submit
Combobox Arrow keys to navigate suggestions, Enter to select, Escape to close listbox
Responsive Navigation Escape to close mobile menu, focus management on open and close
Switch / Toggle Space to toggle the switch on and off
Tooltip Escape to dismiss tooltip, tooltip appears on focus

// 07 · next steps

Next Steps

Keyboard testing is one slice of a complete accessibility audit. Once you can navigate every flow with the keyboard alone, work through the Accessibility Testing Checklist for a structured pass that layers screen reader, visual, and cognitive checks on top of keyboard testing. To catch the mechanical failures before you start testing by hand, wire up automated accessibility testing so axe, Lighthouse, or Pa11y flag the obvious issues in CI.