Skip to main content

Keyboard Navigation

Not everyone has the ability to properly use a mouse and relies on keyboard navigation. Keyboard navigation can work natively in HTML, but it requires more steps to make it work properly and to improve the user experience for those users. These users also want to be able to navigate the webpage efficiently.


Prevent keyboard traps

For example, when creating a dialog, check if it is possible to navigate out of the dialog just by using keyboard navigation. The close button should be accessible, otherwise users that rely on keyboard navigation only will get stuck in the dialog. Often it is also possible to exit views using the ESC key.

Focus order

Pages have a certain order when tabbing through them. It is important to help users that rely on keyboard navigation can easily navigate around. When there are a lot of places to navigate through, you can add shortcuts for keyboard navigation to skip to a certain point. This could be in the form of a button that is only accessible through keyboard navigation to skip the focus to a specific part of the page.

Tab-indexes

The tabindex attribute controls how users navigate through interactive elements using the keyboard — typically the Tab key. It determines which elements can receive focus and in what order.
Used correctly, it ensures smooth, predictable keyboard navigation for everyone, including screen reader and keyboard-only users.
Used incorrectly, it can break accessibility and make a page impossible to navigate. It can also create an unpredictable tab order which the user might not expect.


Examples

✅ Correct

<button>Save</button>
<a href="#">Cancel</a>
<input type="text" placeholder="Name" />

❌ Incorrect

<div role="button" tabindex="0" aria-pressed="false">
Custom Button
</div>

✅ Correct

<!-- Focusable only via script -->
<div id="modal" tabindex="-1">Modal content...</div>
// Example: set focus programmatically
document.getElementById('modal').focus();

❌ Incorrect

<input type="text" tabindex="3" placeholder="Email" />
<input type="text" tabindex="1" placeholder="Name" />
<input type="text" tabindex="2" placeholder="Phone" />

Controls

To avoid confusion, it is important to stay consistent with the control scheme of your platform. Tabs are for navigating over your page and use shift + tab to reverse. The arrow keys are often used to navigate within a component. For example, a dropdown.

Space-bar and enter have many uses.

Space-bar

  • Activating buttons
  • (Un)checking buttons or checkboxes
  • Scrolling down the page
  • Expand a dropdown menu

Enter

  • Activating buttons
  • Opening links
  • Open menus

It shouldn't be necessary to make custom keybinds. If a key does not what you expect, you may be using the wrong kind of HTML element. You can style a link to make it look like a button, but then when you press space-bar, it will not do anything. In that case you need enter. In this case for consistency, use a button instead of a link. Another example is styling a div as a button and adding an onClick. Consider using a button instead.


Summary

👍 Do's

  • Create shortcuts — This will give the user options to efficiently navigate the page.
  • Test with the keyboard only — ensure you can reach and activate every control using Tab, Shift+Tab, Enter, and Space.
  • Check if dialogs or pages can be closed using keyboard only — To prevent users from getting stuck.
  • Use tabindex="0" for custom interactive components (like dropdowns or accordions) that aren’t naturally focusable.
  • Use tabindex="-1" when you want an element to be focusable only via JavaScript (e.g., when opening a modal).
  • Keep the natural tab order for standard form controls and links — browsers handle it well by default.
  • Combine with ARIA roles for custom widgets:
    <div role="button" tabindex="0" aria-pressed="false">Toggle</div>
  • Manage focus deliberately when opening dialogs, popups, or overlays (set focus to the first interactive element).

👎 Don'ts

  • Don’t use positive tabindex values (like tabindex="1" or higher).
  • Don't override keybinds — This will create confusion because users expect a certain keybind.
  • Don't create custom buttons — For example, an <a> styled as a button. An <a> has a different keybind. They create an unnatural and confusing focus order.
  • Don’t make non-interactive elements focusable unless they act like a control (e.g., a custom button).
  • Don’t trap focus inside a component unless it’s intentional (e.g., a modal). But make sure the user can still exit the component using keyboard only.
  • Don’t remove focus outlines with CSS (outline: none;) — they’re essential for keyboard users.
  • Don’t rely on tabindex to fix poor HTML structure. Use semantic elements first.

Extras

Focus management pattern for modals:

// On modal open
modal.setAttribute('tabindex', '-1');
modal.focus();

// Trap focus within modal
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') handleFocusTrap(e);
});

Visually indicate focus clearly also for accessibility:

:focus {
outline: 2px solid #0078d7;
outline-offset: 2px;
}

Accessibility tip:
When creating custom widgets, pair tabindex="0" with correct ARIA roles and keyboard interactions so they behave like native controls.


Resources