Design tokens

Summary

Soma's design tokens are the --soma-* CSS custom properties defined in src/css/_tokens.scss, the single styling contract of the library: every component reads them, themes override the color-derived half, and your own CSS can consume them to stay consistent with whatever theme is active. Static scales (type, spacing, radius, density) sit on :root; everything color-derived lives once per theme block.

Using tokens

Read a token anywhere with var(…):

.my-callout {
  padding: var(--soma-space-3) var(--soma-space-4);
  border-inline-start: 3px solid var(--soma-color-primary);
  border-radius: var(--soma-radius-md);
  background: var(--soma-color-primary-subtle);
  color: var(--soma-color-primary-subtle-fg);
}

That exact rule, live (it follows the active theme):

A callout written entirely in tokens: switch themes and it recolors with the rest of the page.

You can override a token on any subtree. Custom properties cascade, and var(…) resolves at the element that uses it, so every Soma component (and any of your own CSS reading the token) inside that subtree follows, while everything outside keeps the theme value:

[data-my-area] {
  --soma-color-link: #b3382c;
}

Themes are exactly this mechanism at page scale: a [data-soma-theme='name'] block overriding tokens for the subtree it is set on; see the custom-theme recipe.

Reference

The complete token surface, grouped as in src/css/_tokens.scss. The Value column is resolved live with getComputedStyle from the loaded stylesheet, so it always shows the active theme and density. Switch either (corner buttons, or the Themes page) and the tables re-resolve.

Type

TokenValue (live)Preview / notes

Spacing

4 px base with a generous top end — Soma's look is whitespace-heavy.

TokenValue (live)Preview / notes

Radius

TokenValue (live)Preview / notes

Density

Vertical rhythm tokens switched by data-soma-density on <html> (comfortable is the default). The values below are live, so cycling density with the corner button updates them. Full mode table on the Density page.

TokenValue (live)Preview / notes

Motion

One duration/easing vocabulary for every transition: fast for hovers and chevrons, base for overlay enters and toasts, slow for drawers and larger movements. Ambient loops (spinner, skeleton shimmer) sit deliberately outside the scale.

TokenValue (live)Preview / notes

Everything below is color-derived and lives once per theme block: the theming surface.

Brand

TokenValue (live)Preview / notes

Page & text

TokenValue (live)Preview / notes

Surfaces

TokenValue (live)Preview / notes
--soma-surface — translucent widget card. The gradient behind this box bleeds through slightly.
--soma-surface-solid — opaque base tier; form controls sit on this.
--soma-surface-raised — one step up the elevation ladder. In the dark theme surfaces lighten with height; in light themes it stays white.
--soma-surface-overlay — top of the ladder: menus, dialogs, toasts and popovers. Switch to the dark theme to see the tiers separate.
--soma-surface-inset — recessed panels: code blocks, log viewer, diff. Deliberately darker than the widget surface so they stay visible on it.
--soma-surface-backdrop — the dialog blanket scrim.

Shadows

Soft, blue-grey tinted elevation. In the dark theme the overlay tiers (-2/-3) add a 1px border-strong edge ring: black shadows barely read on a dark page, so elevation leans on the surface ladder instead. In the high-contrast theme all three become outline rings so white surfaces stay delineated on the white page.

TokenValue (live)Preview / notes
--soma-shadow-1
resting card
--soma-shadow-2
dropdown, popover
--soma-shadow-3
dialog

Semantic sets

Five sets (neutral, success, warning, danger, info), each six slots: the solid fill, its -hover and -active state shades (derived per theme via color-mix), text on the fill (-fg), the tinted variant (-subtle), and text on the tint (-subtle-fg). Fills and their paired foregrounds are contrast-audited together; always use the matching -fg, never a hand-picked color.

TokenValue (live)Preview / notes

The theming surface

The reference above splits in two. The static scales (type, spacing, radius, density) are theme-neutral: declared once on :root, identical in every theme, so layout and rhythm never shift when the theme changes. Everything color-derived (brand, page & text, surfaces, shadows and the five semantic sets, plus the color-scheme declaration and the optional --soma-link-decoration) is the theming surface: the dark and high-contrast blocks restate exactly that set, and a custom theme overrides any subset of it (anything omitted falls back to the light values on :root).

TierGroups
Theme-neutral (never overridden) Type (--soma-font-*, --soma-line-height*), spacing (--soma-space-*), radius (--soma-radius-*), density (--soma-density-*, switched by data-soma-density, not by themes).
Theming surface (restated per theme) Brand (--soma-color-primary*, -link, -focus, --soma-focus-ring, --soma-link-decoration), page & text (--soma-color-page, --soma-page-background, --soma-color-text*, --soma-color-border*), surfaces (--soma-surface*), shadows (--soma-shadow-*), the five six-slot semantic sets (fill, -hover, -active, -fg, -subtle, -subtle-fg), and color-scheme.

The worked [data-soma-theme='acme'] recipe (which tokens to supply and what falls back) is on the Themes page. House law for contributors: any new color-derived token must be declared in all three theme blocks in _tokens.scss; the per-theme axe sweep fails CI if one is missing.