Lesson 6 of 30
A meaningful population of real users never touches a mouse — motor disabilities, screen reader users, power users. If an interactive element can't be reached and operated with a keyboard alone, it doesn't work for them, full stop.
12 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 3
What does adding `tabindex="0"` to a `div` acting as a custom button actually do?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
Keyboard operability is the requirement that every interactive element on a page — every link, button, form field, custom widget — can be reached and activated using only a keyboard. This isn't a niche concern layered on top of "real" UX; it's a baseline a real, sizeable set of users depends on entirely: people with motor disabilities who can't reliably operate a mouse, screen reader users who navigate primarily by keyboard rather than by pointing at things, and plenty of sighted power users who simply find tabbing faster than reaching for a trackpad.
The mechanism browsers use for this is the tab order — the sequence Tab and Shift+Tab step through as a user moves forward and backward across the page's focusable elements. By default, that order follows DOM order: elements are visited in the sequence they appear in the document, not the sequence they appear visually on screen (those two usually match, but not always — CSS can reorder things visually without touching the DOM).
Three tabindex values matter, and they do very different things:
tabindex="0" adds an element that isn't natively focusable (a div acting as a button, say) into the natural tab order, at its normal DOM position.tabindex="-1" makes an element focusable programmatically — reachable via JavaScript's .focus() — but removes it from the natural tab order entirely. A user tabbing through the page will never land on it by pressing Tab. This is the tool for deliberate focus management (moving focus into a dialog, for example), which the next lesson covers in depth.tabindex (tabindex="5", tabindex="12", anything above zero) is a real, common anti-pattern worth naming directly. It doesn't just nudge an element's position — it creates an entirely custom tab order, disconnected from and usually conflicting with the visual and DOM layout. Mix positive tabindex values into a page and the result is a tab order that jumps around unpredictably, often skipping elements the user expected to reach next.<!-- 0: joins the natural tab order at this DOM position -->
<div role="button" tabindex="0" onclick="submit()">Submit</div>
<!-- -1: focusable via JS only, invisible to Tab -->
<h2 tabindex="-1" id="dialog-heading">Confirm deletion</h2>
<!-- Positive tabindex: an anti-pattern, not a fix -->
<input tabindex="3" placeholder="Email" />
<input tabindex="1" placeholder="Name" />
<input tabindex="2" placeholder="Phone" />
The last block is the trap. Someone wanted "Name" reached first, so they hand-numbered the fields — but now the tab order (Name → Phone → Email) is out of sync with the visual layout, and every future field added to this form needs its own carefully chosen number just to avoid breaking the sequence. If a field genuinely needs to be reached earlier, the fix is almost always reordering the DOM to match, not assigning it a lower positive tabindex.
tabindex="0" and tabindex="-1" solve different problems. 0 is for "this should be a normal stop in the tab sequence." -1 is for "this should be focusable by code, but never by pressing Tab." Reaching for the wrong one is a common, easy-to-make mistake.tabindex values compound. One tabindex="1" on a page forces every other positive value to be reasoned about relative to it — the moment a second developer adds a field, the ordering logic has to be reverse-engineered before they can safely insert anything.order or float) doesn't automatically reorder in the tab sequence. Tab order follows DOM order regardless of how something is visually positioned, which is exactly how "the tab order jumps around" bugs get introduced without anyone touching tabindex at all.Enter/Space (common on div-as-button patterns) is still broken for keyboard users even though Tab lands on it correctly."Walk me through what's wrong with this component" — handed a custom dropdown or button built from divs with onClick but no keyboard handling — is a common practical question, and naming tabindex="0" vs. -1 vs. positive values precisely, by their actual mechanics, is what separates a candidate who's memorized "add ARIA" from one who understands what's actually happening.