Focus Visible
Using
:focus-visibleto provide keyboard focus indicators without affecting mouse users.
What is :focus-visible?
:focus-visible is a CSS pseudo-class that applies focus styles only when the browser determines a focus indicator should be visible — typically during keyboard navigation or when using assistive technology. This solves the problem of unwanted focus rings when users click buttons with a mouse.
:focus— applies to any focus method (mouse click, keyboard, programmatic):focus-visible— applies only for keyboard/assistive technology focus
Implementation Pattern
/* Remove default focus ring (safe with :focus-visible below) */
button:focus {
outline: none;
}
/* Show custom indicator for keyboard users */
button:focus-visible {
outline: 3px solid #ffbf47;
outline-offset: 2px;
}
A simpler approach that enhances rather than replaces:
/* Enhance default outline for keyboard focus */
:focus-visible {
outline: 3px solid #0078d4;
outline-offset: 2px;
border-radius: 2px;
}
WCAG Requirements
Focus indicators must meet WCAG 2.1 SC 2.4.7 (Level AA):
- Minimum 3:1 contrast ratio against adjacent colors
- Visible and distinguishable from other UI elements
- Should not obscure other important content
/* ❌ Bad: No focus indicator */
button:focus { outline: none; }
/* ❌ Bad: Poor contrast */
button:focus-visible { outline: 1px solid #ddd; }
/* ✅ Good: High contrast, visible */
button:focus-visible {
outline: 3px solid #0066cc; /* 7:1 contrast on white */
outline-offset: 2px;
}
Browser Support
Modern browsers support :focus-visible natively (Chrome 86+, Firefox 85+, Safari 15.4+). For older environments, use the focus-visible polyfill:
import 'focus-visible';
The polyfill applies a .focus-visible class via JavaScript heuristics, matching the native behavior.
Real-World Impact
An e-commerce site that implemented proper focus indicators saw:
- 72% faster task completion for keyboard users
- 74% reduction in checkout abandonment
Users who couldn't see focus were effectively navigating blind — they couldn't tell where Tab had moved them.
Design Patterns
/* Solid outline (most common) */
:focus-visible {
outline: 3px solid #0078d4;
outline-offset: 2px;
}
/* Box shadow (for elements with rounded corners) */
:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(0, 120, 212, 0.6);
}
/* Inset for buttons with colored backgrounds */
button:focus-visible {
outline: 3px solid #fff;
outline-offset: -4px;
}
/* High-contrast mode support */
@media (forced-colors: active) {
:focus-visible {
outline: 3px solid ButtonText;
}
}
Common Mistake
/* ❌ This removes focus for ALL users including keyboard users */
* { outline: none !important; }
/* ✅ Safe: removes mouse-click ring but keeps keyboard ring */
:focus:not(:focus-visible) { outline: none; }
:focus-visible { outline: 3px solid #0078d4; }
Content from Frontend-Master-Prep-Series — 08-accessibility