2 min read

CSS :focus-visible Pseudo-class

The :focus-visible pseudo-class applies while an element matches the :focus pseudo-class and the user agent (browser) determines via heuristics that the focus should be made evident on the element.

1. The Problem with :focus

Traditionally, the :focus pseudo-class applies whenever an element receives focus, whether by keyboard (Tab key), mouse click, or touch.

This led to a common issue:

  1. Designers/Developers didn't like the default focus ring appearing when users clicked buttons with a mouse.
  2. They removed it using outline: none.
  3. Result: Keyboard users (who rely on the focus ring to know where they are) could no longer navigate the site effectively. This is a major accessibility failure.

2. The Solution: :focus-visible

:focus-visible solves this by letting the browser decide when to show the focus indicator.

  • Keyboard Navigation: If a user tabs to a button, :focus-visible matches (ring shown).
  • Mouse Click: If a user clicks a button, :focus-visible usually does not match (no ring shown), even though :focus does.
  • Text Inputs: Text inputs usually always match :focus-visible because the user needs to see the cursor/focus regardless of input method.

3. Basic Usage

The best practice is to remove the default outline only when :focus is active but :focus-visible is not, or simply define styles specifically for :focus-visible.

/* Default focus style (often reset by browsers/frameworks) */
:focus {
  outline: 2px solid blue;
}

/* 
   Modern approach: 
   Define styles specifically for focus-visible.
   Browsers often default to this behavior now.
*/
button:focus-visible {
  outline: 2px solid blue;
  outline-offset: 2px;
}

button:focus:not(:focus-visible) {
  outline: none;
}

4. Browser Heuristics

The browser uses heuristics to determine if focus should be visible. Generally:

  • True: If the user interacts via keyboard (Tab, Arrow keys).
  • True: If the element is an <input>, <textarea>, or contenteditable="true" (regardless of input device).
  • False: If the user interacts via mouse or touch on non-text elements (buttons, links).

programming/css/css programming/css/pseudo-classes-and-pseudo-elements programming/css/selectors