Focus Ring Design Patterns
Accessible, beautiful focus indicators that work across keyboard, mouse, and touch without compromising your visual design.
The Baseline
Browsers ship default focus rings. They work. They are also ugly and inconsistent. The goal is to replace them with something that feels intentional while preserving — or improving — accessibility.
/* Reset default, then rebuild */
*:focus {
outline: none;
}
*:focus-visible {
outline: 2px solid #8B5CF6;
outline-offset: 2px;
border-radius: 4px;
}The critical distinction: :focus fires for mouse clicks too. :focus-visible only fires when the browser heuristics detect keyboard navigation. Always use focus-visible for rings.
The Glow Variant
For dark interfaces, a box-shadow glow reads better than a hard outline. It blends into the design language instead of fighting it.
*:focus-visible {
outline: none;
box-shadow: 0 0 0 3px rgba(139, 92, 246, 0.5);
border-radius: 6px;
}The Ring-Offset Pattern
A two-layer approach: a thin inner ring plus a translucent outer glow. This works on any background and looks premium.
*:focus-visible {
outline: none;
box-shadow:
0 0 0 2px #0A0612,
0 0 0 4px #8B5CF6;
border-radius: 4px;
}Tailwind Utility Class
Encapsulate the pattern into a reusable class so every interactive element gets consistent treatment.
/* globals.css */
@layer utilities {
.focus-ring {
@apply focus:outline-none focus-visible:ring-2
focus-visible:ring-[#8B5CF6]
focus-visible:ring-offset-2
focus-visible:ring-offset-[#0A0612]
focus-visible:rounded;
}
}Interactive Elements
Apply the utility to links, buttons, inputs, and any custom interactive component. Consistency is the point.
Never Do This
- ✕
outline: nonewithout replacing it. This breaks keyboard navigation entirely. - ✕Using
:focusfor decorative rings. Mouse users will see flashes on every click. - ✕Low-contrast rings. A 1px gray ring on a dark background is invisible to low-vision users.