← All posts

Keyboard Accessibility Guide - WCAG Rules, Tests and Fixes

22 Oct 2026 · 9 min read · keyboard accessibility, wcag, focus, web development

Keyboard accessibility means every part of your website can be reached and used with a keyboard alone, without a mouse or touchpad. If a visitor can press Tab to move through your links, buttons and form fields, see where they are at every step, and activate everything with Enter or Space, your site is in good shape. If they get stuck, lose track of focus, or cannot open a menu, it is not.

This guide covers who depends on keyboard access, the WCAG 2.2 success criteria involved, a five-minute test you can run today, and the code fixes that solve the most common problems.

Who relies on keyboard accessibility?

Far more people use a keyboard (or something that acts like one) than most teams assume:

  • Screen reader users, many of whom are blind, navigate mostly with keyboard commands.
  • People with motor disabilities such as tremors, limited dexterity or paralysis may use a keyboard, switch devices, sip-and-puff controls or head pointers. Most of these tools send keyboard events to the browser.
  • Voice control users often rely on the same focusable elements and accessible names that keyboard access depends on.
  • People with temporary injuries, like a broken wrist, who cannot use a mouse comfortably.
  • Power users who simply prefer the keyboard because it is faster.

If your site works with a keyboard, it is usually much easier to make it work with all of these assistive technologies too.

The WCAG criteria behind keyboard accessibility

The Web Content Accessibility Guidelines (WCAG) include several success criteria that relate directly to keyboard use. Our WCAG checklist covers the full list; these are the ones that matter most here.

CriterionLevelWhat it requires
2.1.1 KeyboardAAll functionality is operable through a keyboard interface
2.1.2 No Keyboard TrapAFocus can always be moved away from any component using the keyboard
2.4.1 Bypass BlocksAA way to skip repeated content, such as a skip link or landmarks
2.4.3 Focus OrderAFocus moves in an order that preserves meaning and operability
2.4.7 Focus VisibleAAThe keyboard focus indicator is visible
2.4.11 Focus Not Obscured (Minimum)AAThe focused element is not entirely hidden by other content (new in 2.2)
2.5.8 Target Size (Minimum)AAPointer targets are at least 24 by 24 CSS pixels, with some exceptions (new in 2.2)

2.1.1 Keyboard and 2.1.2 No Keyboard Trap

Everything a mouse user can do, a keyboard user must be able to do: open menus, play video, submit forms, close dialogs, use sliders and carousels. A keyboard trap happens when focus enters a component, such as an embedded map or a third-party chat widget, and the user cannot Tab or Escape out of it.

2.4.1 Bypass Blocks

Without a skip link, a keyboard user has to Tab through your entire header and navigation on every page before reaching the main content. A "Skip to main content" link as the first focusable element fixes this.

2.4.3 Focus Order and 2.4.7 Focus Visible

Focus should follow the visual reading order, normally left to right and top to bottom. And users must be able to see which element has focus. The most common failure is CSS like outline: none applied to everything with no replacement style.

2.4.11 Focus Not Obscured (new in WCAG 2.2)

Sticky headers, cookie banners and chat bubbles often cover the element that just received focus. WCAG 2.2 requires that the focused element is not completely hidden by author-created content.

2.5.8 Target Size (new in WCAG 2.2)

Strictly a pointer criterion, target size still belongs in any keyboard and motor access review: small, tightly packed controls are hard for people with limited dexterity. The minimum is 24 by 24 CSS pixels, or enough spacing around smaller targets.

Keys keyboard users expect

KeyExpected behaviour
TabMove to the next focusable element
Shift + TabMove to the previous focusable element
EnterActivate a link or button, submit a form
SpaceActivate a button, toggle a checkbox, scroll the page
Arrow keysMove within a component: radio group, menu, tabs, slider, select
EscClose a dialog, menu or popup

Links respond to Enter; buttons respond to both Enter and Space. When you build custom controls, they should follow these same conventions.

A 5-minute keyboard accessibility test

You do not need special tools for this. Put your mouse aside and work through your home page and one key flow, such as checkout or a contact form.

  1. Click in the browser address bar, then press Tab. Is the first stop a skip link? Does it work?
  2. Keep pressing Tab. Can you always see where focus is?
  3. Does focus move in a logical order that matches the layout?
  4. Open the main navigation and any dropdowns using only the keyboard.
  5. Open and close any modal or popup. Does Esc close it, and does focus return to the button that opened it?
  6. Fill in and submit a form, including any error messages.
  7. Check that focus never disappears behind a sticky header or banner.
  8. Confirm you never get stuck inside a widget.

Write down every problem. Then run an automated scan with our free accessibility checker, which flags issues such as positive tabindex values, a missing skip link and controls without accessible names. Automated tools cannot judge focus order or traps, so the manual test still matters. Pair it with screen reader testing for a fuller picture.

How to fix common keyboard accessibility problems

Show a clear focus indicator with :focus-visible

Do not remove outlines without a replacement. :focus-visible shows the ring for keyboard users while browsers generally hide it on mouse clicks.

:focus-visible {
  outline: 3px solid #1a5fb4;
  outline-offset: 2px;
}

Make sure the indicator has enough contrast against the background. Our guide to color contrast accessibility explains the ratios.

Use a real button, not a div

A div with a click handler is not focusable and does not respond to Enter or Space. A native button does all of this for free.

<!-- Avoid -->
<div class="btn" onclick="save()">Save</div>

<!-- Use -->
<button type="button" onclick="save()">Save</button>

Likewise, use a href for navigation and button for actions.

Add a skip link

<a class="skip-link" href="#main">Skip to main content</a>
...
<main id="main" tabindex="-1">...</main>
.skip-link { position: absolute; left: -9999px; }
.skip-link:focus { left: 1rem; top: 1rem; }

Make dropdown menus keyboard friendly

Use a button to toggle each submenu and expose its state with aria-expanded. The submenu should open on Enter or Space, close on Esc, and return focus to the toggle.

<button aria-expanded="false" aria-controls="products-menu">Products</button>
<ul id="products-menu" hidden>
  <li><a href="/widget">Widget</a></li>
</ul>

Avoid menus that open only on hover.

Handle focus in modals

When a modal opens, move focus into it. While it is open, keep Tab cycling inside it. When it closes, return focus to the trigger. The native dialog element opened with showModal() handles much of this, including closing on Esc.

const dialog = document.querySelector('dialog');
openBtn.addEventListener('click', () => dialog.showModal());
dialog.addEventListener('close', () => openBtn.focus());

Stop sticky headers hiding focus

If you have a fixed header, scroll-padding-top keeps focused elements and anchor targets from sliding underneath it.

html { scroll-padding-top: 5rem; }

Use tabindex correctly

  • tabindex="0" adds a custom element to the natural tab order.
  • tabindex="-1" makes an element focusable from script, but not with Tab.
  • Positive values like tabindex="3" override the natural order and almost always create confusing focus order. Remove them and fix the DOM order instead.

ARIA patterns basics

For complex widgets such as tabs, accordions, comboboxes and menus, the W3C ARIA Authoring Practices Guide (APG) documents the expected roles, states and keyboard interactions. A few rules keep you safe:

  • Native HTML first. Elements like button, select, details and dialog come with keyboard support built in.
  • ARIA changes semantics, not behaviour. Adding role="button" does not make an element focusable or respond to keys; you must add tabindex="0" and key handlers yourself.
  • Use roving tabindex for composite widgets. In a tab list, only the active tab has tabindex="0"; the others have -1, and arrow keys move between them.
  • Keep states in sync. Update aria-expanded, aria-selected and aria-checked whenever the UI changes.

On platforms like WordPress and Shopify, theme and plugin choice has a big effect on keyboard support; see our WordPress accessibility guide for practical tips.

Frequently asked questions

What is keyboard accessibility?

Keyboard accessibility means that every link, button, form field and interactive feature on a website can be reached and operated using only a keyboard, with a visible focus indicator and a logical order. It is required by WCAG success criterion 2.1.1 and supports screen reader users, people with motor disabilities and many others.

How do I test my website for keyboard accessibility?

Put the mouse away and use Tab, Shift+Tab, Enter, Space, the arrow keys and Esc to move through your pages. Check that focus is always visible, follows a logical order, never gets trapped, and that menus, modals and forms all work. Then run an automated scan to catch code-level issues like positive tabindex values.

Is it okay to remove the focus outline?

Only if you replace it with another clearly visible focus style. Removing outlines entirely fails WCAG 2.4.7 Focus Visible. The :focus-visible pseudo-class lets you show a strong indicator for keyboard users without showing it on every mouse click.

What changed for keyboard users in WCAG 2.2?

WCAG 2.2 added 2.4.11 Focus Not Obscured (Minimum), which requires that a focused element is not completely hidden by things like sticky headers, and 2.5.8 Target Size (Minimum), which sets a 24 by 24 CSS pixel minimum for pointer targets with some exceptions. It also added an enhanced focus appearance criterion at level AAA.

Can an accessibility widget make my site keyboard accessible?

A widget can help, for example by adding a stronger focus outline, but it cannot fix a div that should be a button, a keyboard trap in a third-party embed, or a menu that only opens on hover. Those need code changes. Read the truth about accessibility widgets for more detail.

Conclusion

Keyboard accessibility is one of the most important and most testable parts of web accessibility. Use native elements, keep a visible focus style, add a skip link, manage focus in menus and modals, and avoid positive tabindex. Then test with your keyboard regularly. To find code-level issues in minutes, run your pages through our free accessibility checker, then work through the fixes above.

Is your website accessible?

Run a free WCAG check, or add the Openwise widget with one line of code.

Check my website Get started free