Home / Snippets / Accessibility /
focus-visible focus ring
Show focus rings for keyboard users, hide them for mouse clicks.
Try clicking vs. pressing Tab to see the difference.
Quick implementation
/* Global focus ring — apply to all interactive elements */
:focus-visible {
outline: 2px solid oklch(0.52 0.22 265);
outline-offset: 3px;
}
/* Remove ring on mouse/touch click */
:focus:not(:focus-visible) {
outline: none;
}
/* Dark mode: brighter ring for contrast */
@media (prefers-color-scheme: dark) {
:focus-visible {
outline-color: oklch(0.7 0.2 265);
}
}
/* High contrast: thicker ring */
@media (forced-colors: active) {
:focus-visible {
outline: 3px solid LinkText;
}
}
Prompt this to your LLM
Includes role, constraints, and edge cases.
You are a senior frontend engineer focused on accessibility.
Goal: A global focus ring system that only shows for keyboard navigation.
Technical constraints:
- Use :focus-visible for keyboard-triggered focus.
- Use :focus:not(:focus-visible) { outline: none } to hide ring on mouse click.
- Outline: 2px solid accent color, 3px offset.
- Use oklch() for the outline color.
- Include @media (prefers-color-scheme: dark) with a brighter outline color.
- Include @media (forced-colors: active) for Windows High Contrast mode — use system colors.
- The outline must NEVER be removed without a replacement — WCAG 2.4.7 requires visible focus.
- outline-offset creates breathing room between the element and the ring.
Apply globally via :focus-visible on :root or *, and override per-component if needed.
Return CSS only.
Why this matters
Focus rings are the #1 accessibility requirement designers want to remove — and the #1 thing keyboard users need to navigate. :focus-visible solves the conflict: the ring shows only when the browser detects keyboard navigation (Tab key), not mouse clicks. Both groups are happy.
The logic
:focus-visible matches when the browser determines focus should be visible — typically after keyboard interaction. :focus:not(:focus-visible) matches mouse/touch focus and removes the outline. The outline-offset: 3px creates visual space between the element and ring, making it look intentional rather than like a browser default.
Accessibility & performance
WCAG 2.4.7 (Focus Visible) requires a visible focus indicator. Never use outline: none without :focus-visible — that removes focus for keyboard users. In forced-colors mode, use system color keywords (LinkText, Highlight) since custom colors are overridden. Zero performance cost — outlines are painted on the compositor layer.