Eunomia v1.1.0
AllAngularReactNext.jsJavaScriptVue
EunomiaSalmonForestVioletOceanGoldFireCustom…
🇬🇧 English🇫🇷 Français

Neutral tokens

Surface, text, and border tokens shared by every brand. Each one is a named alias onto a specific step of the grey scale, so they automatically flip between light and dark along with it.

Token Swatch Maps to
--eun-surface-color --eun-color-grey-0
--eun-border-color / --eun-divider-color --eun-color-grey-300, text mixed 12% into the surface in dark mode
--eun-disabled-color --eun-color-grey-200
--eun-content-hover translucent overlay
--eun-content-pressed translucent overlay
--eun-text-color --eun-color-grey-800
--eun-text-secondary --eun-color-grey-600 (light), #d2d5de (dark)
--eun-readonly-color / --eun-text-readonly-color --eun-color-grey-600 / --eun-color-grey-400
--eun-placeholder-color / --eun-text-disabled-color / --eun-disabled-content --eun-color-grey-400 / --eun-color-grey-500 / --eun-color-grey-400

Usage

These are the tokens to reach for in almost all app-level CSS: they carry semantic meaning ("this is the surface color") and stay correct across every brand and mode, unlike reaching for a raw grey step directly.

.custom-card {
  background: var(--eun-surface-color);
  color: var(--eun-text-color);
  border: 1px solid var(--eun-border-color);
}

.custom-card[aria-disabled="true"] {
  background: var(--eun-disabled-color);
  color: var(--eun-text-disabled-color);
}

This is exactly the pattern eun-button's disabled state and eun-tab-group's divider use internally. See Theming for how the whole token cascade fits together.

These values only apply once a theme stylesheet is loaded: see Foundation → Import for how to load it per framework.

Brand-tinted variants

The tokens above are deliberately brand-independent: --eun-surface-color is the same white (light) / grey-0 (dark) no matter which prebuilt theme is active, so a component built against it never clashes with any brand.

Each one also has a -tint counterpart that mixes a small amount (5%) of the active theme's primary-500 into that same base value. These stay opt-in and are not used by any component internally, so reach for them only when you deliberately want a surface, divider, or hover wash that reads as "branded" rather than neutral.

Token Swatch Derived from
--eun-surface-tint --eun-surface-color + 5% primary
--eun-border-tint / --eun-divider-tint --eun-border-color + 5% primary
--eun-content-hover-tint --eun-content-hover + 5% primary
--eun-content-pressed-tint --eun-content-pressed + 5% primary
.branded-card {
  background: var(--eun-surface-tint);
  border: 1px solid var(--eun-border-tint);
}

.branded-card:hover {
  background: var(--eun-content-hover-tint);
}

Text and disabled/readonly tokens intentionally don't get a tint variant: those carry a legibility or muted-state contract that a brand wash would work against.

Translucent variants

For overlays, frosted headers, or muted text that must let the content underneath show through, the theme also exposes the surface and text colors at fixed opacities. They are computed with color-mix() from --eun-surface-color and --eun-text-color, so they follow the active brand and mode without any extra work.

Token Derived from
--eun-surface-transparent-25 / -50 / -75 --eun-surface-color at 25%, 50% and 75%
--eun-text-transparent-25 / -50 / -75 --eun-text-color at 25%, 50% and 75%
--eun-text-on-dark-secondary white at 70%, the same in light and dark

--eun-text-on-dark-secondary is the one exception to the "follows the theme" rule. Use it for muted text on a surface that stays dark whatever the active mode, such as a footer.

.sticky-header {
  background: var(--eun-surface-transparent-75);
  backdrop-filter: blur(8px);
}

.dark-footer {
  color: var(--eun-text-on-dark-secondary);
}

For an elevated surface in dark mode, reach for --eun-surface-tint above.

Inverse surface

Some elements stay dark whatever the active mode: a dark toolbar, a footer, a highlighted section. Their background is a role rather than a brand color, so it gets its own tokens instead of a third color scale.

Token Swatch Value
--eun-surface-inverse #0b1620 in both modes
--eun-text-on-inverse #f5f7fa in both modes
--eun-text-on-inverse-secondary --eun-text-on-inverse at 70%
--eun-border-on-inverse --eun-text-on-inverse at 20%
--eun-content-hover-on-inverse --eun-text-on-inverse at 8%
--eun-content-pressed-on-inverse --eun-text-on-inverse at 14%
--eun-backdrop-color --eun-surface-inverse at 45%

eun-toolbar and eun-link use them by default with theme="dark". A custom theme sets the surface with the inverseSurfaceColor option of buildThemeCss, which also picks a readable --eun-text-on-inverse. The last five are computed with color-mix() and follow it. --eun-backdrop-color is the dimmed layer behind eun-modal and eun-drawer.

.site-footer {
  background: var(--eun-surface-inverse);
  color: var(--eun-text-on-inverse);
  border-top: 1px solid var(--eun-border-on-inverse);
}

.site-footer small {
  color: var(--eun-text-on-inverse-secondary);
}

Sunken surfaces

Tracks, wells and filled containers need to read one step below whatever they sit on: the toggle group's track, the switch and slider tracks, an unchecked checkbox, a filled card, a collapse, a flat button. A fixed grey step can't do that: a grey-100 surface disappears into a grey-100 page. The sunken tokens are a translucent wash of --eun-text-color instead, so they darken a light background and lighten a dark one, and stay visible on any container. Nested sunken surfaces stack, so a track inside a collapse still reads one step darker than the collapse.

Token Swatch Light Dark
--eun-surface-sunken --eun-text-color at 5% --eun-text-color at 8%
--eun-surface-sunken-hover --eun-text-color at 9% --eun-text-color at 12%
--eun-surface-sunken-pressed --eun-text-color at 12% --eun-text-color at 16%
--eun-surface-sunken-strong --eun-text-color at 8% --eun-text-color at 16%

Dark mode uses a stronger mix because a light wash over a dark surface reads fainter than a dark wash over a white one.

--eun-surface-sunken is meant for bordered controls and for containers. A borderless track (the slider, progress bar, password strength and loader bars) has nothing but its fill to show where it is, so it uses --eun-surface-sunken-strong instead.

.custom-track {
  background: var(--eun-surface-sunken);
}

.custom-track:hover {
  background: var(--eun-surface-sunken-hover);
}

Reach for --eun-surface-color or another opaque color for anything that floats or must hide what is behind it (a popover, a toast, a tooltip, a sticky header), and for the sunken tokens for a control that sits inside a surface. Like the translucent variants, they are resolved where the theme is declared: a section that redefines --eun-text-color on its own does not update them.