Skip to content

:focus-visible CSS — Smart Focus Indicators

DodaTech Updated 2026-06-28 3 min read

In this tutorial, you will learn about :focus. We cover key concepts, practical examples, and best practices to help you master this topic.

The :focus-visible pseudo-class provides smart focus indicators that appear during keyboard navigation but not mouse clicks, giving both keyboard and mouse users an optimal experience.

In this tutorial, you'll master Focus Management with :focus-visible.

What You'll Learn

By the end of this lesson, you'll understand how :focus-visible works, how to use the :focus-visible-within Polyfill, and how to create focus indicators that adapt to input modality.

Why It Matters

Mouse users do not need persistent focus rings. :focus-visible removes visual noise for mouse users while providing clear indicators for keyboard users.

Real-World Use

DodaTech uses :focus-visible across all web properties, showing focus rings only during keyboard navigation.

How :focus-visible Works

flowchart TD
  A[User interacts] --> B{Input method?}
  B -->|Keyboard Tab| C[Browser applies :focus-visible]
  B -->|Mouse click| D[Browser does not apply :focus-visible]
  B -->|Keyboard arrow| C
  B -->|Programmatic focus| E[Browser decides]
  C --> F[Show custom focus ring]
  D --> G[Hide focus ring]
  E --> H[Varies by browser]

Implementing :focus-visible

/* Primary: keyboard-only focus */
:focus-visible {
  outline: 3px solid #0066CC;
  outline-offset: 2px;
}

/* Remove default focus for mouse users */
:focus:not(:focus-visible) {
  outline: none;
}

/* Specific element styles */
button:focus-visible {
  outline: 3px solid #0066CC;
  border-radius: 4px;
}

a:focus-visible {
  outline: 3px dashed #0066CC;
  outline-offset: 4px;
}

input:focus-visible {
  outline: 3px solid #0066CC;
  outline-offset: -1px;
}

Fallback for Older Browsers

/* Fallback: always show outline */
:focus {
  outline: 3px solid #0066CC;
}

/* Modern: only show for keyboard */
:focus:not(:focus-visible) {
  outline: none;
}

:focus-visible {
  outline: 3px solid #0066CC;
}

Testing :focus-visible

// Check if :focus-visible is supported
const supportsFocusVisible = CSS.supports('selector(:focus-visible)');

// Programmatically check focus visibility
element.addEventListener('focus', (event) => {
  const isFocusVisible = event.target.matches(':focus-visible');
  console.log('Focus visible:', isFocusVisible);
});

Common Mistakes

  • Removing :focus without providing :focus-visible: Keyboard users lose focus indication.
  • Assuming :focus-visible behaves the same everywhere: Browser heuristics differ.
  • Not providing a fallback: Older browsers without :focus-visible support need :focus fallback.
  • Overriding :focus-visible browser defaults incorrectly: Let the browser decide when focus should be visible.
  • Not testing with both mouse and keyboard: Verify behavior with both input methods.

Practice and Challenge

1. When does :focus-visible apply? During keyboard navigation, not mouse clicks.

2. What is the difference between :focus and :focus-visible? :focus applies always. :focus-visible applies when the browser determines it should be visible.

3. How do you handle browsers that do not support :focus-visible? Provide a :focus fallback.

4. How do you detect :focus-visible support? CSS.supports('selector(:focus-visible)').

5. Challenge: Implement :focus-visible with a fallback on your website. Test with keyboard and mouse.

FAQ

Does :focus-visible work for programmatic focus?

It depends. Some browsers apply :focus-visible for element.focus(), others do not.

Can I force :focus-visible with JavaScript?

No. The browser determines :focus-visible based on input modality.

Does :focus-visible work in all browsers?

All modern browsers support it. Provide a :focus fallback for IE and older browsers.

Should I use :focus-visible on all elements?

Yes, on all interactive elements that should show a focus indicator.

Can I use :focus-visible with custom widgets?

Yes. Custom widgets with tabindex support :focus-visible.

Mini Project

Implement a complete :focus-visible system for a page with buttons, links, inputs, and custom widgets. Include a fallback for non-supporting browsers.

What's Next

Continue to Programmatic Focus to learn about element.focus() and its options.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro