Lesson 12 of 30
The old :focus selector couldn't tell a keyboard tab from a mouse click, which pushed teams toward the same broken workaround: strip focus styles entirely. :focus-visible fixes the actual problem.
10 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 problem does `:focus-visible` solve that plain `:focus` couldn't?
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
:focus matches an element whenever it has keyboard focus, full stop — it doesn't distinguish how that focus happened. Click a button with a mouse and it matches :focus exactly the same as tabbing to it with a keyboard. That's the real UX problem: a focus ring is genuinely useful for someone navigating by keyboard (it's the only visual signal of where they are on the page), but the same ring showing up on every mouse click reads as a visual glitch to most users, since a click already carries its own strong "I clicked this" feedback.
Faced with that binary, a lot of real production sites picked the worse option: outline: none on everything, killing the focus ring entirely. That "fixes" the mouse-click flicker but silently breaks the page for every keyboard and assistive-technology user — someone tabbing through a form with no visible focus indicator has no way to tell where they are. This is a real, still-common accessibility failure, not a hypothetical one.
:focus-visible solves it properly. The browser applies its own heuristic — informed by input modality, not just focus state — for "was this focus likely the result of keyboard or assistive-tech navigation," and the pseudo-class only matches then. A mouse click on a button generally won't trigger :focus-visible; tabbing to that same button will.
/* Old approach: either show a ring on every click (annoying)
or strip it everywhere (an accessibility failure) */
button {
outline: none; /* do NOT ship this alone */
}
/* Correct approach: no ring styling decision needed for :focus,
restyle specifically for the keyboard-navigation case */
button:focus-visible {
outline: 2px solid var(--color-accent);
outline-offset: 2px;
}
/* Optional: explicitly clear the default ring for the non-keyboard case,
now that :focus-visible covers the case that actually needs it */
button:focus:not(:focus-visible) {
outline: none;
}
The middle rule is the fix: it keeps a visible ring exactly when the browser judges the focus came from keyboard/assistive-tech navigation, and leaves mouse-click focus alone. The last rule is a common companion pattern — it explicitly clears the browser's own default :focus ring for the non-:focus-visible case, so you're not fighting the user agent stylesheet.
:focus-visible is Baseline / widely supported now — there's no meaningful reason left to reach for outline: none without it, or to reach for the older :focus-within/JS-based "detect keyboard vs. mouse" workarounds this pseudo-class was built to replace..focus() calls) is implementation-defined, so don't design UI that depends on :focus-visible matching a specific input device with 100% certainty.:focus-visible replacement is not. The failure mode isn't styling the ring differently, it's leaving keyboard users with zero visible indicator at all.tabindex, natural focusability, .focus()); :focus-visible only changes when a style applies, not when focus itself happens."Why would you use outline: none on a button, and what's wrong with doing that?" is a real question used to check whether a candidate can name the concrete accessibility failure it causes and knows :focus-visible is the fix, not just that "removing outlines is bad practice" as a vague rule.