Keyboard-only

Principle: All interactive elements can be accessed by keyboard alone.

Using a keyboard is a fundamental aspect of accessibility. In fact, many other technologies and hardware emulate keyboard functionality. Users with a wide range of disabilities — or no disability at all — rely on a keyboard. When testing, keep in mind that all interactive elements should be accessible with the keyboard.

Sections

Keyboarding basics

  • Use the Tab key to navigate in a linear direction through focusable elements like links, form controls, and buttons.
  • The Enter key (and sometimes Spacebar) selects an element.
  • Arrow keys are used to move within certain elements, element groups, and widgets. For example, within form select elements, radio button groups, and a set of tabs.
  • For a more comprehensive list of actions, review this table of common keyboard interactions.

If you're testing in Safari or Firefox in macOS, you'll likely have to update a few settings so that all focusable elements can receive focus; details below. The resources section contains additional links with more details on enabling keyboard navigation for focusable elements.

For Firefox:

  1. Go to System Preferences > Keyboard > Shortcuts.
  2. Check the "Use keyboard navigation to move focus between controls" option.
macOS keyboard settings

For Safari:

  1. Open Preferences > Advanced.
  2. Check the "Press Tab to highlight each item on a webpage" option.
Safari browser advanced settings

Focus order

The focus order is the sequence that a keyboard user tabs through focusable elements. In most cases the focus order and DOM order should be the same. Visually reordering elements with CSS, such as with floats, flexbox, or grid, can be problematic for focus order, so ensure content makes sense both visually and linearly in the markup. To learn more about what elements should be focusable by default read this Introduction to Focus.

Example navigation with tab order overlays
Example tab order moving through navigation

Some HTML elements, like form elements and buttons, receive focus by default because they have native event handling. In these cases nothing has to be done for them to be in the focus order. That being said, it’s possible to use the tabindex attribute to make elements focusable.

  • tabindex="-1": This makes an element programmatically focusable, but doesn’t include it in the tab order.
  • tabindex="0": This inserts and element into the focus order in the order of the DOM.
  • tabindex="1"+: This adds a higher focus priority and isn’t recommended due to a negative cascading effect

Expected behavior

  • Only interactive elements are focusable, not static content.
  • Focus order follows the DOM order and reading order.
  • When a navigational menu is in an expanded state that reveals more links, the focus should move through those links before moving on.
  • For widgets such as assignee dropdowns:
    • Its popup element appears either on focus, or when pressing Enter, Space, or Down Arrow.
    • The arrow keys move focus within the widget.
    • Enter accepts the selected value and optionally closes the popup. Focus remains on the widget.
    • Esc closes the popup and focus remains on the widget.
    • Tab leaves the widget and focus moves to the next interactive element or widget. Tab should not move focus within a widget since widgets are treated as a single interactive element.
  • The focus order of a page should complete a loop and return back to the browser’s address bar.

Identifying problems

  • The focus order bounces around the page or doesn’t follow the expected reading flow.
    • Inspect the DOM order to determine what the linear content flow is.
    • If there are no issues with the DOM order, inspect the CSS to see if floats, flexbox, or grid are visually reordering elements.
    • If the DOM order and CSS don’t seem to be impacting the flow, check to see if any elements have tabindex set to a value of 1 or higher.
  • An element receives focus, but shouldn’t.
    • Check to see if the element has the tabindex attribute and it’s set to 0 or higher.
  • An element doesn’t receive focus, but should.
    • It’s possible that focus is received, but a visible focus state is missing, see the section on Focus States for more.
    • If the element is custom, or not one that natively receives focus it should have tabindex set to 0.
  • Focus gets trapped somewhere in the page and can’t complete a loop back to the browser’s address bar.
  • Focus seems to disappear when tabbing.
    • Elements that are visually hidden, like a mobile menu in a desktop view, can still receive focus if they don’t use a method which also removes them from the focus order. Use an extension, like NerdeFocus for Chrome, to reveal where focus is being placed.
    • In CSS, display: none; or visibility: hidden; are good ways to remove focus. The element could also have the tabindex="-1" or hidden attributes added.

Focus states

Every focusable element must have a visible focus state for keyboard navigation. Typically a focused element has a stronger border, glow, or shadow to highlight it. Browsers provide a focus ring by default, but this can be removed or enhanced with CSS.

One button with a custom focus ring, and another with browser default
Buttons with custom and browser default focus rings

Expected behavior

When an element receives focus with the keyboard, it’s visually distinct from both its other states and other elements.

Identifying problems

An element has focus, but there’s no visual indication.

  • Inspect the CSS to see if outline is set to none without adding styles to the :focus state.
  • A utility like What Input? can detect the input method (mouse, keyboard, or touch) and provide ways to change focus styles based on the input method. Make sure you’re using a keyboard for the input method and that no utilities are interfering with the styles.

Keyboard traps

A keyboard trap keeps the focus order looping within a section. A modal, for example, uses a keyboard trap to prevent a user from focusing on content elsewhere in the page — content that could even be hidden by the modal itself. There should never be a keyboard trap that a user can’t get out of.

A modal with overlays showing how focus is trapped within the modal
A modal with a keyboard trap and multiple ways to dismiss

Expected behavior

  • After encountering a keyboard trap a user should be able to “untrap” the focus with the Esc key, a close button, or other action that navigates the user away from the current experience.
  • When the user exits the keyboard trap (without page reload or navigating away) the focus should return to the previously focused element, usually the one that triggered the keyboard trap in the first place.

Identifying problems

  • An element like a modal or dialog that overlays other content is activated, but the focus can leave that element, and even focus on items covered by it.
    • A keyboard trap should be created and controls should exist to close the element and return focus to its previous location.
  • An item that should be a keyboard trap never receives focus.
    • Custom elements should have tabindex="-1" set and focus should be programmatically placed in them from the triggering element.

Skip links are anchor links placed before a section that allow a user to bypass blocks of repeating page sections (typically navigation), and "skip" to the main content. They’re typically not visible until they receive focus, and then they’re visible for all users.

Skip link visible when focused in the GitLab header navigation
Skip link with focus in GitLab’s primary navigation

Expected behavior

  • A skip link is typically the first focusable item on the page and should take a user to the main content area.
  • Skip links should be minimally used, if multiple are present there may be other navigation or content issues.

Resources

Last updated at: