HuntExams Academy logo
HTML/CSSAdvanced#css#pseudo-classes#accessibility

What is the difference between :focus and :focus-visible?

Answer

:focus applies to any focused element, including after a mouse click, which can produce unwanted outlines. :focus-visible applies only when the browser determines focus should be visibly indicated — typically from keyboard navigation — giving cleaner UX for mouse users while preserving accessibility for keyboard users.

Example

button:focus { outline: none; } /* removes for all */
button:focus-visible { outline: 2px solid blue; } /* only shows for keyboard nav */

Detailed explanation

:focus and :focus-visible are CSS pseudo-classes for styling focused elements, but they answer different questions. :focus means “Does this element currently have focus?” :focus-visible means “Does this focused element need a visible focus indicator according to the browser?” Focus identifies the element that receives keyboard input or interaction. The distinction matters because users navigating with Tab need to see their location, while pointer users may not need an additional indicator after clicking a button.

:focus matches regardless of how focus was obtained: keyboard navigation, a pointer interaction that focuses the element, or JavaScript calling focus(). Clicking does not focus every element in every browser or platform. Also, :focus does not itself create an outline; browser default styles or your CSS provide that appearance. For example, button:focus { outline: 2px solid blue; } adds an outline whenever that button is focused. In contrast, button:focus { outline: none; } removes the outline for every focus method unless another applicable rule restores it.

:focus-visible also requires focus, but matching depends on browser heuristics rather than a strict “keyboard only” rule. Keyboard navigation typically triggers it. Text-entry controls, such as text inputs, commonly match even after a mouse click because users need keyboard input to operate them. User preferences and the context of programmatic focus changes can also influence matching. Both pseudo-classes have equal specificity, so when rules target the same element and property, the rest of the cascade—including source order—determines the result.

For accessible styling, provide a clearly visible indicator with button:focus-visible { outline: 2px solid blue; outline-offset: 2px; }, choosing a colour that contrasts against surrounding backgrounds. If default pointer-focus outlines must be suppressed, button:focus:not(:focus-visible) { outline: none; } is safer than unconditionally removing all focus outlines: browsers without :focus-visible support ignore that selector and retain their defaults. The supplied example works in supporting browsers when the second rule wins, but lacks that fallback protection. Interviewers look for the difference between focus state and indicator heuristics, the text-input exception, and awareness that hiding indicators without a reliable replacement harms keyboard accessibility.

Key points to remember

  • :focus matches an element whenever it has focus, regardless of the focus method.
  • :focus-visible matches a focused element when browser heuristics call for a visible indicator.
  • :focus-visible is not keyboard-only; clicked text inputs commonly match too.
  • Both pseudo-classes have equal specificity; normal cascade rules resolve competing declarations.
  • Preserve a clear keyboard focus indicator and retain default outlines where support is unavailable.

Common mistakes candidates make

  • Saying :focus-visible matches only after Tab navigation or never after a mouse click.
  • Removing outlines with :focus without providing a reliable, accessible replacement.
  • Assuming :focus creates outlines itself or that every mouse click focuses its target.

Likely follow-up questions

How can I style focus while preserving a fallback for older browsers?

Define a visible button:focus outline first, then remove it with button:focus:not(:focus-visible) { outline: none; }. Browsers that do not support :focus-visible ignore the removal rule and keep the fallback.

Does calling element.focus() always trigger :focus-visible?

No; programmatic focus does not guarantee a :focus-visible match. Browser heuristics consider factors such as the target control and whether focus was visibly indicated before the change.

How does :focus-within differ from these pseudo-classes?

:focus-within matches an element when it or a descendant has focus. It is useful for highlighting a form group containing the active input, whereas :focus and :focus-visible match the focused element itself.

Interview tip: Explain focus state versus browser indicator heuristics, then demonstrate a button and a text input using both keyboard and mouse.

Related Interview Questions

1
HTML/CSSIntermediate#css#accessibility

How do you make an SVG icon accessible and stylable with CSS?

Open
2
HTML/CSSAdvanced#css#responsive

What is the difference between em/rem and viewport-relative clamp() for fluid typography?

Open
3
HTML/CSSAdvanced#css#responsive

What are container queries and how do they differ from media queries?

Open