HTMLKeyboard Navigation & tabindex

Keyboard Navigation and tabindex

Many users cannot use a mouse at all — including screen reader users, people with motor impairments, and power users who simply prefer the keyboard. Every interactive element on a page must be reachable and operable using only Tab, Shift+Tab, Enter, Space, and arrow keys.

Natural tab order from the DOM

By default, pressing Tab moves focus through every focusable element in the order they appear in the DOM — not their visual position on screen. Native interactive elements (a, button, input, select, textarea) are focusable automatically; most others are not.

HTML
<!-- Tab order follows this exact top-to-bottom order -->
<a href="/">Home</a>
<button>Search</button>
<input type="text" />
The tabindex attribute

Value

Effect

tabindex="0"

Adds the element to the natural tab order, at its DOM position — the standard way to make a custom element focusable

tabindex="-1"

Removes the element from the Tab key sequence, but still allows it to receive focus programmatically (e.g. via JavaScript .focus())

tabindex="1" or higher

Forces the element to the front of the tab order, ahead of everything with tabindex="0" or none — an anti-pattern

HTML
<!-- Custom interactive element, made keyboard-focusable -->
<div role="button" tabindex="0" onclick="save()">Save</div>

<!-- Focusable via script only (e.g. a heading you move focus to after a route change) -->
<h1 tabindex="-1" id="page-title">Search Results</h1>
Warning
Avoid positive tabindex values entirely. They create a separate, manually-ordered tab sequence that almost never matches the visual or DOM layout, and becomes a maintenance nightmare as the page changes — one new positive tabindex anywhere reshuffles the whole page's tab order.
Focus-visible styling

Browsers draw a default focus outline (or "ring") around the currently focused element. Removing it with outline: none and providing nothing in its place is a serious accessibility failure — keyboard users lose all sense of where they are on the page.

CSS
/* Bad: focus indicator removed with nothing to replace it */
button:focus {
  outline: none;
}

/* Good: custom focus style, still clearly visible */
button:focus-visible {
  outline: 2px solid #2563eb;
  outline-offset: 2px;
}
  • :focus-visible applies a style only for keyboard (and similar) focus, not for a mouse click — letting you keep clean mouse interactions while preserving keyboard visibility.

  • Never set outline: none without a replacement focus style of comparable visibility.

  • Custom focus styles should have enough contrast against the background to be seen by low-vision users.

Skip links

A skip link is the very first focusable element on a page, hidden visually until focused, letting keyboard users jump straight past repeated navigation to the main content.

HTML
<a href="#main-content" class="skip-link">Skip to main content</a>

<nav>... long navigation menu ...</nav>

<main id="main-content">
  ...
</main>

CSS
.skip-link {
  position: absolute;
  left: -9999px;
}
.skip-link:focus {
  left: 8px;
  top: 8px;
  z-index: 100;
}

Without a skip link, a keyboard user must tab through every navigation item on every single page before reaching the main content — a serious friction point on content-heavy sites.

Tip
Test keyboard navigation yourself: unplug your mouse (or just don't touch it) and try to complete a core task on your page using only Tab, Shift+Tab, Enter, and arrow keys. Anything you can't reach or operate is a real accessibility bug.
Note
Interactive elements that are visually hidden with display: none or visibility: hidden are automatically removed from the tab order — no tabindex management needed for content that is genuinely hidden.