Theming
Every visual choice in Eunomia, colors, spacing, corner rounding, shadows, fonts, comes from a single design system rather than being fixed inside each component. Switch the active brand or flip between light and dark, and everything on the page updates immediately: no rebuild, no page reload, no per-component work. That's what lets this whole site re-theme itself live from the toolbar above, and it's the same mechanism your own app gets, whether you install one of the 7 prebuilt themes as-is or generate a custom one from your own brand colors.
How tokens are named
Every one of those values, a color, a spacing value, a font size, is
exposed as a small, named unit called a token. In plain CSS terms
a token is just a variable: a name that stands in for a value,
so the actual color or size only has to be defined once and can then
be reused, and swapped, everywhere. Every token name starts with
--eun- and follows the same shape after that, --eun-[what it is]-[which variant], for example --eun-color-primary-500 (the
primary brand color, at its "500" shade), --eun-space-m (a medium
spacing value), or --eun-fontSize-s (a small font size). Learn a
handful of these and you can usually guess the name of any other one.
Because tokens are plain CSS, not compiled values baked in ahead of time, switching a theme never needs a rebuild: the browser just looks up the same token names against a different set of values.
How switching works
Two independent attributes on <html> control the active theme:
<html data-brand="eunomia" data-theme="light"></html>
data-brandselects one of the 7 prebuilt palettes (eunomia,salmon,forest,violet,ocean,gold,fire), orcustom.data-themeislightordark.
The toolbar at the top of this site sets both attributes live. Try switching brand or mode with it: everything below reacts instantly, with no reload. The choice persists (via `localStorage`) across pages and reloads.
these three all read straight off the active brand/mode
This differs slightly from how the underlying component library ships
its CSS: there, each prebuilt theme is a .eunomia-<name>-theme /
.eunomia-<name>-theme--dark class you add to <body>, meant to be
combined with a separate base .eunomia-theme class for full token
coverage (fonts, spacing, radius, shadows; the class alone only
carries colors). This site instead compiles each theme's full token
bundle into one [data-brand][data-theme] selector
(styles/eunomia-themes.scss), so a single attribute pair is always
enough. See
For component authors
Reference tokens directly. Never hardcode a color, size, or radius:
.eunomia-button {
background: var(--eun-color-primary-500);
color: var(--eun-color-on-primary-500);
border-radius: var(--eun-borderRadius-m);
padding: var(--eun-space-xs) var(--eun-space-m);
font-family: var(--eun-font-family);
}
.eunomia-button:hover {
background: var(--eun-color-primary-600);
}
Because the token exists on every brand and mode, the component repaints correctly no matter which theme is active. Nothing in the component itself needs to know about brands or dark mode.
Sections
7 ready-made palettes to preview and pick from
Build your own palette from two brand colors
How colors adapt automatically between light and dark mode
The shared colors every theme has in common