Theming
Every surface, glow, and gradient resolves from CSS custom properties. Switch modes with one attribute, or retheme by overriding tokens.
How Themes Work
Themes are controlled by the data-theme attribute on the <html>element. ARC UI ships three modes:
data-theme="dark"Default. Deep blacks with blue/violet accent glows.data-theme="light"Bright backgrounds with stronger accent colors.data-theme="auto"Follows OS prefers-color-scheme preference.Every component adapts on the spot when the theme changes, with no configuration needed. Try it: flip the toggle in the top bar.
Dark Mode
Dark mode is the default: near-black surfaces with blue and violet accent glows.
<!-- Dark mode is the default — no attribute needed -->
<html>
<!-- or explicitly: -->
<html data-theme="dark">
The surface stack, rendered live:
--bg-deep--bg-surface--bg-card--bg-elevatedLight Mode
Light mode shifts backgrounds to soft whites and strengthens the accents for contrast on light surfaces. Shadows become blue/violet-tinted instead of black.
<html data-theme="light">
Auto Mode
Auto mode follows the user's OS preference via prefers-color-scheme. To persist an explicit choice across visits, store it and restore on load:
// Set theme and persist
function setTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
localStorage.setItem('arc-theme', theme);
}
// Restore on page load
const saved = localStorage.getItem('arc-theme') || 'auto';
document.documentElement.setAttribute('data-theme', saved);
arc-theme-toggle component handles this automatically. Drop it into your layout.Fixed Regions
Some regions (navs, footers, a command bar) should hold their appearance regardless of the page theme. .theme-fixed-dark and .theme-fixed-lightpin a subtree to one scheme. Not a separate palette: the same scheme the library generates for :root, applied to a subtree instead. So a pinned region carries exactly the contrast that scheme was tuned for.
<div class="theme-fixed-dark">
<arc-top-bar fixed>
<!-- Dark tokens, whatever the page is doing -->
</arc-top-bar>
</div>
<aside class="theme-fixed-light">
<!-- and the reverse, for a light panel on a dark page -->
</aside>
Each class has two landing points. On a page of its own scheme a pinned region is that scheme: a dark nav on a dark page is plain near-black. On a page of the other scheme it is not allowed to go all the way, because a black slab against near-white is a harder boundary than anything else on the page; it lands instead on a deep colour derived from your accent. The top bar and footer here do exactly that: flip to light mode and watch them land on blue rather than black.
--accent-primary and its lightness
from the scheme, so overriding your accent re-colours pinned regions with it. A teal
brand gives a deep teal nav; a monochrome one stays grey. There is no second palette
to keep in step.
Custom Themes
Compound tokens (gradients, glows, focus rings) reference the base accent tokens viavar(). Override the base pair (plus their -rgb channel variants, which alpha compositing needs) and everything downstream follows:
:root {
--accent-primary: rgb(0, 150, 136);
--accent-primary-rgb: 0, 150, 136;
--accent-secondary: rgb(233, 30, 99);
--accent-secondary-rgb: 233, 30, 99;
/* That's it. Glows, gradients, and focus rings recompose from these. */
}
Here are those four lines applied to this page, live: every button, glow, gradient, and divider follows:
Theme Synthesizer
The Theme Synthesizer lets you tweak every token, preview the result in real time, and download a ready-to-use base.css.
See Also
- Tokens: design token reference
- Theme Synthesizer: visually build a custom theme
- Theme Toggle: component for switching themes