Design Tokens
Lyse UI uses a 3-layer token architecture built with CSS custom properties. Tokens handle colors, typography, spacing, and layout across light and dark modes.
Architecture
Tokens flow through 3 layers. Each layer adds meaning and abstraction:
Layer 1: Primitives (root-*.css)
--root-color-brand-500, --root-space-4, --root-font-size-base
↓
Layer 2: Semantics (semantic-*.css)
--background-brand-strong-default, --text-base-strong
↓
Layer 3: Bridge (shadcn-bridge.css)
--primary, --foreground, --ringComponents consume Layer 2 tokens in their .css files and Layer 3 tokens via Tailwind utilities.
Layer 1: Primitives
Raw values with no semantic meaning. These are the foundation that everything builds on.
root-colors.css — 5 scales (brand, danger, neutral, success, warning) with 50–950 steps each.root-typography.css — Font sizes, weights, and line heights.root-layout.css — Spacing, radius, borders, opacity, and sizing./* Examples */
--root-color-brand-500: #6366f1;
--root-space-4: 1rem;
--root-font-size-base: 0.875rem;
--root-radius-md: 8px;Layer 2: Semantics
Named by purpose, not value. Semantic tokens reference primitives and remap between light and dark mode.
semantic-colors.css — Background, text, border, and icon tokens with light/dark values.semantic-global.css — Mode-independent aliases for spacing, sizing, and layout.typography.css — Composite utility classes like .text-content-body and .text-heading-small./* Light mode (:root) */
--background-brand-strong-default: var(--root-color-brand-500);
--text-base-strong: var(--root-color-neutral-900);
/* Dark mode (.dark) */
--background-brand-strong-default: var(--root-color-brand-400);
--text-base-strong: var(--root-color-neutral-50);Layer 3: Bridge
Maps Lyse semantic tokens to shadcn variable names. This is what makes Lyse components compatible with the shadcn ecosystem and Tailwind utilities.
/* shadcn-bridge.css */
--primary: var(--background-brand-strong-default);
--foreground: var(--text-base-strong);
--ring: var(--border-brand-default);
--destructive: var(--background-danger-strong-default);These bridge variables are registered in globals.css via @theme inline, making them available as Tailwind utilities like bg-primary and text-foreground.
Usage
Components use Layer 2 tokens in their CSS files for theming, and Layer 3 tokens via Tailwind utilities for layout:
/* button.css — Layer 2 tokens for theming */
.button-primary {
background: var(--background-brand-strong-default);
color: var(--text-inverse);
}
.button-primary:hover {
background: var(--background-brand-strong-hover);
}{/* button.tsx — Layer 3 via Tailwind */}
<button className="rounded-md bg-primary text-primary-foreground">
Click me
</button>For spacing and layout, use the layout tokens: var(--layout-padding-*), var(--layout-gap-*), var(--layout-radius-*).
Dark mode
Semantic tokens automatically remap when the dark class is present on any ancestor element. No component changes needed — the token layer handles everything.
/* :root = light mode (default) */
:root {
--text-base-strong: var(--root-color-neutral-900);
}
/* .dark = dark mode */
.dark {
--text-base-strong: var(--root-color-neutral-50);
}