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.
<!-- 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 |
<!-- 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>
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.
/* 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.
<a href="#main-content" class="skip-link">Skip to main content</a> <nav>... long navigation menu ...</nav> <main id="main-content"> ... </main>
.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.
display: none or visibility: hidden are automatically removed from the tab order — no tabindex management needed for content that is genuinely hidden.