"Unplug your mouse for a day. Try to use your own site. The bugs you find are the ones every keyboard-only user lives with."
Why Keyboard Matters Beyond Accessibility
Keyboard navigation isn't just for users with motor disabilities. Every power user uses keyboard shortcuts. Every screen-reader user is, by definition, navigating with keys. Every dev tool, every IDE, every productivity app lives or dies on keyboard speed. Designing for the keyboard from the start makes the site faster for everyone.
The Default Tab Order
By default, Tab moves through every focusable element in document order. Focusable elements include:
<a href>(anchors with href)<button>(buttons of any type)<input>,<textarea>,<select>(form fields)<details>/<summary>(disclosure widget)- Any element with
tabindex="0"
If your page is built with semantic elements, the tab order is correct by accident. The reverse is also true: if your interactive things are <div>s, they're invisible to Tab.
tabindex: The Three Values That Make Sense
tabindex="0"— "include this in the natural Tab order." Use to make a non-focusable element focusable (a custom interactive widget). Most common legitimate use of tabindex.tabindex="-1"— "focusable via JavaScript, but not via Tab." Use for elements you want to programmatically focus (an error message after submit, the title of a modal you just opened) without inserting them into the Tab order.- Anything positive (1, 2, 5...) — bad. Forces a custom order that overrides natural document order. Becomes unmaintainable the moment the DOM changes; surprises users who expect Tab to follow visual order. Don't.
Focus Management: Moving Focus Intentionally
When the user takes an action that changes the page significantly, focus should follow. Examples:
- Open a modal — move focus into the modal (usually its heading or first input). When closed, return focus to the element that opened it.
- Submit a form with errors — move focus to the first invalid field, or to a summary error region.
- Successfully save — announce "Saved" in a live region; for big actions, move focus to a confirmation heading.
- Navigate via SPA route change — move focus to the new page's
<h1>(SPAs don't get the browser's automatic focus-to-top behavior).
Use element.focus() to move focus. Pair with a tabindex="-1" on the target if it's not natively focusable (a heading, a paragraph) — the -1 makes it programmatically focusable without putting it in the Tab order.
:focus vs :focus-visible
For decades, every focused element got a focus ring on every focus event — including mouse clicks. Designers hated it ("ugly outline after I click my own button"); a generation of CSS shipped with outline: none to remove the ring, which broke keyboard users.
:focus-visible solved it. The browser decides: keyboard navigation → show the ring; mouse click → don't. You can finally style focus rings beautifully without breaking accessibility:
outline: none without replacing it. If you remove the default focus ring, replace it with something equally visible (a custom outline, a box-shadow, a background change). Use :focus-visible as the selector so mouse clicks don't trigger it. Pages that ship outline: none with no replacement are uncrawlable for keyboard users.Skip Links: The 60-Second Accessibility Win
Every page has a header, navigation, and sometimes a sidebar before <main>. Keyboard users would have to Tab through all of it on every page load. A skip link is the first focusable element, normally hidden, that becomes visible on focus and lets the user jump straight to main content:
Focus Trap For Modals
When a modal opens, focus should be trapped inside it — Tab from the last element loops to the first, Shift+Tab from the first loops to the last, and the user can't reach the page behind. The native <dialog> element handles this automatically. Roll-your-own modals need JavaScript to set this up — which is yet another reason to prefer <dialog>.
The Audit That Catches Everything
Unplug your mouse for one hour and use your own site. Try to log in, post a comment, navigate menus, change a setting. Every bug you find is a bug a keyboard-only or screen-reader user lives with daily. This single hour will teach you more than any documentation.