:focus-visible CSS — Smart Focus Indicators
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
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