CSS :focus-visible vs :focus Styling Fix
In this tutorial, you'll learn about CSS :focus. We cover key concepts, practical examples, and best practices.
The Problem
The :focus-visible pseudo-class applies focus styles only when the browser determines the focus should be visible (typically keyboard navigation). When :focus is used instead of :focus-visible, focus outlines either show for every click (annoying) or are removed entirely (inaccessible).
Quick Fix
Step 1: Use :focus-visible for keyboard-only focus
/* Wrong — outline shows on every click */
button:focus {
outline: 2px solid blue;
}
/* Wrong — outline removed entirely (inaccessible) */
button:focus {
outline: none;
}
/* Right — visible only for keyboard users */
button:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
Step 2: Provide fallback for older browsers
/* Wrong — no fallback for :focus-visible support */
button:focus-visible {
outline: 2px solid blue;
}
/* Right — use @supports with fallback */
button:focus {
outline: 2px solid blue; /* Fallback for all browsers */
}
@supports (selector(:focus-visible)) {
button:focus {
outline: none; /* Remove when :focus-visible is supported */
}
button:focus-visible {
outline: 2px solid #6366f1;
outline-offset: 2px;
}
}
Step 3: Custom focus styles that work for everyone
.custom-button {
background: #f0f0f0;
border: 2px solid transparent;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
}
/* Wrong — no visible focus indicator */
.custom-button:focus {
outline: none;
}
/* Right — subtle focus ring for all, stronger for keyboard */
.custom-button:focus-visible {
outline: 3px solid #6366f1;
outline-offset: 2px;
box-shadow: 0 0 0 2px #fff, 0 0 0 5px #6366f1;
}
Step 4: Style focus within components
/* Wrong — focus style only on the input, not the container */
.form-group input:focus-visible {
outline: 2px solid blue;
}
/* Right — enhance the container when child has focus */
.form-group:focus-within {
border-color: #6366f1;
box-shadow: 0 0 0 3px rgba(99, 102, 241, 0.2);
}
.form-group input:focus-visible {
outline: none; /* Remove default, rely on container */;
}
Step 5: Never use :focus { outline: none } alone
/* WRONG — this is the most common accessibility bug */
*:focus {
outline: none;
}
/* ACCEPTABLE — only if paired with :focus-visible */
*:focus {
outline: none;
}
*:focus-visible {
outline: 2px solid currentColor;
}
Prevention
- Use
:focus-visibleinstead of:focusfor keyboard focus indicators - Always provide a visible focus indicator — never remove it entirely
- Use
outlinefor focus — notbox-shadowalone (outline does not affect layout) - Test focus with keyboard (Tab key) on every interactive element
- Use
outline-offsetto separate the focus ring from the element
Common Mistakes with focus visible
- Overlapping type class instances that cause GHC to reject the program with ambiguous dispatch errors
- Non-exhaustive pattern matches that compile with warnings then crash at runtime
- Misunderstanding that
Stringis[Char]with poor performance for large text operations
These mistakes appear frequently in real-world CSS code. DodaTech's contributors have identified these patterns through analysis of open-source projects and production systems.
Practice Exercise
Write a pure function that safely divides two integers using Maybe, then test it with edge cases like division by zero and negative numbers.
This exercise reinforces the concepts covered in this guide. Try implementing it before checking online solutions.
FAQ
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro