Theming

The srui token contract — every variable, what it drives, and how to override it.

srui components never hard-code colors, shadows or motion. Everything routes through CSS custom properties defined in @iammikz/srui/theme.css and overridden per preset. This page is the complete reference.

Color tokens

Set in theme.css under :root / .dark, aliased to Tailwind utilities via @theme inline:

TokenTailwind utilityNotes
--background / --foregroundbg-background / text-foregroundpage-level
--card / --card-foregroundbg-card / text-card-foregroundmust equal --background in the neumorphic preset
--popover / --popover-foregroundbg-popover / text-popover-foregrounddialogs, dropdowns, tooltips
--primary / --primary-foregroundbg-primary / text-primary-foreground
--secondary / --secondary-foregroundbg-secondary / text-secondary-foreground
--muted / --muted-foregroundbg-muted / text-muted-foregroundde-emphasized text, skeleton base
--accent / --accent-foregroundbg-accent / text-accent-foregroundhover states
--destructive / --destructive-foregroundbg-destructive / text-destructive-foreground
--success / --success-foregroundbg-success / text-success-foregroundour extension to shadcn's set
--warning / --warning-foregroundbg-warning / text-warning-foregroundour extension
--info / --info-foregroundbg-info / text-info-foregroundour extension
--borderborder-border
--inputbg-input (at low opacity, e.g. bg-input/30)
--ringvia outline-ring, never ring-* (see below)
--sidebar* (7 tokens, mirrors the main set)bg-sidebar, etc.for AppShell
--chart-1 … --chart-8referenced directly as stroke/fill in chart SVGsnot Tailwind classes

Surface recipe tokens

Structure, not color — every preset overrides all five. The surface utility composes them; it never sets background-color, so it composes with bg-card / bg-popover / bg-primary in any stylesheet order.

TokenUsed byMeaning
--surface-shadowsurface utility, resting state
--surface-shadow-hovercomponents with a hover elevation change (hover:shadow-(--surface-shadow-hover))
--surface-shadow-pressedactive/pressed state (active:shadow-(--surface-shadow-pressed))
--surface-blursurface utility's backdrop-filter0px except glass
--surface-imagesurface utility's background-imagegradients/highlights; none except glass and skeuomorphic

Motion tokens

TokenValueUsed for
--dur-fast120msmicro-interactions (input focus)
--dur-base200msdefault transitions (button, card hover)
--dur-slow500mslarge state changes
--ease-outcubic-bezier(0.2, 0.8, 0.2, 1)default easing
--ease-springcubic-bezier(0.34, 1.56, 0.64, 1)dialog/popover entrance

Radius tokens

--radius holds the preset's base value and is aliased to --radius-sm / --radius-md / --radius-lg / --radius-xl via @theme inline — the rounded-sm … rounded-xl utilities follow the active preset automatically.

Animation utilities

Registered in animations.css under @theme, usable as plain classes: animate-draw, animate-grow-y, animate-grow-x, animate-shimmer, animate-spin-slow, animate-count-fade, animate-scale-in, animate-fade-in. srui always pairs them with motion-safe: so reduced-motion users get the final state instead of a stuck animation.

Overriding a token

Redefine the variable after the @imports — the last definition wins for your whole app:

@import "tailwindcss";
@import "@iammikz/srui/theme.css";
@import "@iammikz/srui/presets/flat.css";

/* your brand */
:root {
  --primary: oklch(0.55 0.18 295);
  --radius: 0.75rem;
}
.dark {
  --primary: oklch(0.7 0.15 295);
}

To scope an override to one subtree, set the variable on any wrapper — custom properties inherit, so everything inside re-themes (this is exactly how <PresetGrid> on the Introduction page shows four presets at once).

Dark mode

UIProvider toggles a dark class on <html> based on its scheme state ("light" | "dark" | "system"), persisted under the srui-scheme localStorage key. Every token above has a .dark variant in each preset. Setting data-style on a wrapper (not <html>) re-themes just that subtree — but .dark always applies at the page level.

Token playground

Change --primary, --radius and --background and watch the preview update live:

Tokens

These controls only redefine the tokens on the preview wrapper — nothing is persisted.

Preview card
Watch it restyle as you change tokens.