Skip to content

Theming

Stash colors come in three buckets. Use them in this order.

Token buckets

  1. Semantic tokens — role names like primary, surface, text, success. Use these for almost everything. When a product color changes, it changes here once and every screen follows.
  2. Primitives — the raw ramp (--stash-color-blue-500 and the rest), shown on the Colors page. Use a primitive only when no role fits — a brand gradient, a decorative fill, a one-off.
  3. Data-visualization palette--stash-color-viz-1 through viz-8, a categorical sequence for charts. A chart series is not a UI role, so this bucket is exempt from the "prefer semantic" guidance.

Using semantic tokens

With Tailwind, write the semantic utility instead of a raw family utility: bg-primary, not bg-blue-500; text-muted-foreground, not text-ice-700. The content roles use shadcn-style utility names so the default text utility is not text-text.

RoleTailwind utilityCSS variable
Page backgroundbg-surface--stash-color-surface
Card / panelbg-surface-raised--stash-color-surface-raised
Body texttext-foreground--stash-color-text
Secondary texttext-muted-foreground--stash-color-text-muted
Default borderborder-border--stash-color-border
Faint borderborder-border-subtle--stash-color-border-subtle
Primary actionbg-primary text-primary-foreground--stash-color-primary
Tinted primarybg-primary-subtle text-primary-subtle-foreground--stash-color-primary-subtle
Linktext-link--stash-color-link
Success / warning / error / infobg-{role}, bg-{role}-subtle, text-{role}-subtle-foreground, border-{role}-border--stash-color-{role}*

Without Tailwind, read the CSS variables directly: color: var(--stash-color-text).

Dark mode

Add the .dark class to a root element (usually <html>); remove it for light. The :root values are light; a .dark block overrides them. Because a utility like bg-surface compiles to background-color: var(--color-surface) (which resolves to --stash-color-surface), it picks up the dark value on its own — no dark: variant needed. Apps that never add .dark render exactly as before.

To author an explicit dark: override for a one-off, add this once at the top level of your Tailwind entry (not inside a layer()-wrapped import):

css
@custom-variant dark (&:where(.dark, .dark *));

Live examples

Toggle this site's light/dark switch and watch these flip.

surface / foreground
surface-raised
muted-foreground
primary
primary-subtle
success-subtle
warning-subtle
error-subtle
info-subtle

Mapping to other frameworks

Semantic tokens are plain CSS variables, so any framework that themes through CSS variables can point its own names at ours. Do this in the consuming app, not in Stash.

shadcn/ui

Each shadcn variable maps to one Stash token. Set them in the app's global stylesheet:

css
:root {
  --background: var(--stash-color-surface);
  --foreground: var(--stash-color-text);
  --card: var(--stash-color-surface-raised);
  --card-foreground: var(--stash-color-text);
  --popover: var(--stash-color-surface-overlay);
  --popover-foreground: var(--stash-color-text);
  --primary: var(--stash-color-primary);
  --primary-foreground: var(--stash-color-primary-foreground);
  --secondary: var(--stash-color-surface-sunken);
  --secondary-foreground: var(--stash-color-text);
  --muted: var(--stash-color-surface-sunken);
  --muted-foreground: var(--stash-color-text-muted);
  --accent: var(--stash-color-primary-subtle);
  --accent-foreground: var(--stash-color-primary-subtle-foreground);
  --destructive: var(--stash-color-error);
  --destructive-foreground: var(--stash-color-error-foreground);
  --border: var(--stash-color-border);
  --input: var(--stash-color-border-strong);
  --ring: var(--stash-color-focus-ring);
}

Bootstrap (--bs-*)

Bootstrap 5.3 and later theme through CSS variables and support [data-bs-theme] for dark mode. Point the --bs-* variables at Stash tokens:

css
:root {
  --bs-body-bg: var(--stash-color-surface);
  --bs-body-color: var(--stash-color-text);
  --bs-border-color: var(--stash-color-border);
  --bs-primary: var(--stash-color-primary);
  --bs-success: var(--stash-color-success);
  --bs-warning: var(--stash-color-warning);
  --bs-danger: var(--stash-color-error);
  --bs-info: var(--stash-color-info);
}

Bootstrap before 5.3 themes through Sass variables ($primary), so an older app needs a Sass bridge or has to override compiled values. Confirm the version first.

Angular Material (--mat-sys-*)

Angular Material 3 (Angular v17 and later) exposes system CSS variables. Point them at Stash tokens:

css
:root {
  --mat-sys-surface: var(--stash-color-surface);
  --mat-sys-on-surface: var(--stash-color-text);
  --mat-sys-primary: var(--stash-color-primary);
  --mat-sys-on-primary: var(--stash-color-primary-foreground);
  --mat-sys-error: var(--stash-color-error);
  --mat-sys-outline: var(--stash-color-border);
}

Material 2 themes through Sass (define-palette), so the same version caveat applies.