Accent Color and Form Controls
Use accent-color to theme native checkboxes, radios, ranges, and progress — what it paints, what it skips, and when to custom-style instead.
- css
- accent-color
- forms
Native form controls used to fight your brand: blue checkboxes on one OS, grey ranges on another. accent-color is the smallest lever that recolors the browser’s accent chrome on supported controls without rebuilding the whole widget.
Docs: MDN accent-color, CSS UI Module.
What it actually paints
:root {
accent-color: #0b6bcb;
}
/* Or scope it */
.form-branded {
accent-color: var(--brand);
}
Typical hits (browser-dependent, but this is the mental model):
| Control | Effect of accent-color |
|---|---|
input[type="checkbox"] |
Checked fill / mark chrome |
input[type="radio"] |
Selected disc |
input[type="range"] |
Thumb and/or track accent |
progress |
Filled portion |
Some input[type="checkbox"] switches |
Platform-dependent |
It does not restyle text fields, select menus, file pickers, or every pixel of a control. Borders, focus rings, and label text stay under your normal CSS (or the UA stylesheet).
<label>
<input type="checkbox" name="terms" />
Accept terms
</label>
<input type="range" min="0" max="100" value="40" />
<progress max="100" value="60">60%</progress>
One declaration on a parent is often enough — accent-color inherits.
Mental model
Think brand tint for native affordances, not a design-system replacement. You keep:
- Platform rendering and hit targets
- Built-in keyboard and AT behavior
- Less JS than a fully custom checkbox
You give up pixel-perfect parity across Safari/Chrome/Firefox and OS themes. That’s usually fine for product UIs that already accept platform variance.
Pairing with real form CSS
.field {
display: flex;
align-items: center;
gap: 0.5rem;
accent-color: var(--brand-600);
}
.field input[type="checkbox"] {
width: 1.125rem;
height: 1.125rem;
}
.field:focus-within {
/* Don’t rely on accent-color for focus — style :focus-visible on the control */
}
Focus is separate. Use :focus-visible outlines (or a design token ring). accent-color is not a focus indicator and must not replace one.
Contrast matters: a pale accent on a white page can fail WCAG for non-text UI components. Check the filled state against adjacent backgrounds.
When not to stop at accent-color
Build custom controls (with care) when you need:
- Animated checkmarks, indeterminate art, or multi-state chips
- Identical rendering in design QA across OSes
- Complex switch labels that the native control can’t express
Custom means you own keyboard, aria-checked, hit area (≥24×24 CSS px guidance), and high-contrast mode. For a settings form, native + accent-color usually wins.
/* Optional: only when the engine supports it */
@supports (accent-color: red) {
form {
accent-color: var(--brand);
}
}
Unsupported engines ignore the property; controls stay UA-colored. That’s progressive enhancement, not a bug.
Color-scheme interaction
:root {
color-scheme: light dark;
accent-color: light-dark(#0b6bcb, #6cb6ff);
}
Dark mode can wash out a light-only brand blue. Prefer a token that adapts, or set accent-color under prefers-color-scheme / a .theme-dark class.
Interview out-loud
“accent-color sets the accent used by some native form controls — checkboxes, radios, ranges, progress. It inherits, so one rule on the form is enough. It doesn’t restyle text inputs or replace focus styles. I’d use it for light branding of native widgets; for full visual control I’d build accessible custom controls and accept the extra a11y work.”
Footguns
- Assuming every control and every browser matches your Figma file.
- Using a low-contrast brand color and calling it “done.”
- Removing outlines because “the accent looks focused.”
- Fighting
appearance/ vendor pseudo-elements andaccent-colorwithout a clear fallback path. - Forgetting
forced-colors/ Windows High Contrast — custom paints break more often than native.
Related
- Forms, labels, and inputs
- Outline vs border for focus
- prefers-color-scheme
- Theming with custom properties
Further reading
Related guides
- Auto-fit vs Auto-fillauto-fit collapses empty tracks; auto-fill keeps them. Use both with minmax for responsive card grids without media-query soup.
- BEM Naming MethodologyBlock, Element, Modifier naming for CSS — how it limits specificity wars, what to name, and when utility or CSS modules beat strict BEM.
- blend-mode Basicsmix-blend-mode vs background-blend-mode — how pixels combine, isolation, and the stacking/readability traps in product UI.
- box-sizing border-boxWhy border-box makes width include padding and border, the global reset pattern, and the layout bugs content-box still causes.
- Cascade Layers @layerUse @layer to order reset, base, components, and utilities so specificity wars lose — layer priority, unlayered CSS, and !important.