CSS :focus-visible vs :focus - Keyboard-Only Focus Rings
Understand the practical difference between :focus and :focus-visible. Suppress focus rings for mouse clicks while preserving accessibility for keyboard and AT users.
Detailed Explanation
What's Actually Different
:focus matches whenever an element has DOM focus, regardless of how that focus arrived — keyboard, mouse, touch, or scripted element.focus(). :focus-visible defers to the user agent's heuristic for whether a visible indicator should be drawn. In practice that means:
| Interaction | :focus |
:focus-visible |
|---|---|---|
| Tab key | yes | yes |
| Click on a button | yes | no |
| Click on a text input | yes | yes |
element.focus() after a key event |
yes | yes |
element.focus() after a click |
yes | no |
The intent: keep the ring for keyboard and assistive-tech users, hide it for pointer users who don't need it.
Recommended Pattern
/* Universal default — always polite */
:focus { outline: none; }
/* Keyboard-only ring */
:focus-visible {
outline: 2px solid Highlight;
outline-offset: 2px;
}
Using Highlight (a system color keyword) automatically respects the user's OS theme and high-contrast settings.
Don't Suppress Focus Without :focus-visible
The classic anti-pattern is *:focus { outline: none } with nothing to replace it. That makes the page literally unusable for keyboard users, which is a WCAG 2.1 SC 2.4.7 failure.
Inputs Are an Exception
Form fields like <input type="text"> and <textarea> always show :focus-visible — even on click — because typing requires knowing where the caret is. This is intentional UA behavior; don't fight it.
Browser Support
Chrome 86+, Firefox 85+, Safari 15.4+. The behavior was actually built into Chrome much earlier behind a flag, and Safari shipped it last. Any user on a modern browser today gets it.
Use Case
Apply the :focus / :focus-visible split on every interactive component: buttons, links, custom toggles, dropdown items, and tab triggers. It's the single best change you can make to satisfy designers (no orange ring after every click) without hurting keyboard accessibility.