Focus Ring
FrontAlign's components — Button, Dropdown, Input, and others — have always shipped with a deliberate keyboard focus state: a colored outline plus a soft glow, tuned per semantic color. Focus Ring utilities take that exact styling out of the components and make it available on anything you build yourself, from a plain link to a <div tabindex="0"> acting as a custom card.
<button class="btn focus-ring">Save changes</button>
<div tabindex="0" class="custom-card focus-ring-info">...</div>
Your own interactive elements end up indistinguishable from native FrontAlign components at the one moment accessibility actually depends on it: when someone is navigating by keyboard.
Why :focus-visible, Not :focus
Every Focus Ring class is scoped to :focus-visible rather than :focus. The distinction matters: :focus-visible only matches when the browser determines the user is navigating by keyboard or assistive technology — a mouse click or a tap doesn't trigger it. This mirrors how modern browsers already draw their own native focus indicators, so a sighted mouse user never sees a ring appear on click, while a keyboard user always does.
.focus-ring:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
box-shadow: 0 0 0 4px oklch(from var(--accent) l c h / 0.25);
}
Anatomy of the Ring
Each variant combines two layers, deliberately kept separate:
outline— a crisp, 2px solid line, offset 2px from the element's edge. Becauseoutline(unlikebox-shadow) is respected by forced-colors / Windows High Contrast Mode, the ring never silently disappears for users relying on that setting.box-shadow— a soft 4px glow at 25% opacity, generated directly from the same color token via theoklch(from ...)relative color syntax. There's no separate-alphaor-glowtoken to keep in sync — the glow is always exactly the outline color, just translucent.
The result reads as one cohesive ring, but survives edge cases (high-contrast mode, dark backgrounds, colored surfaces) that a single box-shadow-only approach tends to fail.
Available Variants
Five variants ship out of the box, each mapped to one of FrontAlign's semantic color tokens.
| Class | Token | Use for |
|---|---|---|
.focus-ring | --accent | General-purpose focus state — links, inputs, default buttons |
.focus-ring-danger | --danger | Destructive actions — delete, remove, revoke access |
.focus-ring-warning | --warning | Actions that need a second look — irreversible but non-destructive |
.focus-ring-success | --success | Confirming actions — save, approve, submit |
.focus-ring-info | --info | Informational triggers — tooltip anchors, help icons |
Customizing the Ring Color
Because every variant reads its color directly from a theme token rather than a hardcoded value, changing the ring project-wide is a theme change, not a CSS override.
export default {
theme: {
accent: '#7c3aed',
danger: '#dc2626'
}
}
Note that .focus-ring reads --accent, not --primary — the two tokens are intentionally kept separate so your brand's primary action color and its focus-indication color can differ. If you want them to match, set accent to the same value as primary in your theme.
Using It on Non-Interactive Elements
Any element can receive keyboard focus and a matching ring, as long as it's given a tabindex:
<div
tabindex="0"
role="button"
class="custom-card focus-ring"
onclick="handleSelect()"
>
<h3>Pro Plan</h3>
<p>$29/month</p>
</div>
Pairing tabindex="0" with role="button" (and a matching keydown handler for Enter/Space in your own JS) makes a <div> fully keyboard-operable — the Focus Ring utility then ensures it's also keyboard-visible.