Theme Contract
What a theme must override to restyle the library without touching components.
Themes override tokens, not selectors. The themes in src/css/themes/ are demo examples, not shipped by the default stylesheet; they exist to show valid ways to use this contract. A minimal recolor theme overrides the intent pairs, surfaces, text colors, border, focus, focus ring, and hover overlay. Shape, shadow, motion, typography, and soft-variant mix tokens are optional knobs. Override them only when the theme actually changes that part of the system. A full theme can override:
- intent colors and foreground pairs
- surface, text, border, focus, and overlay colors
- radius tokens
- optional shadow, motion, typography, and soft-variant mix tokens
CSS
[data-theme="brand"] {
color-scheme: light;
--primary: hsl(260 70% 54%);
--primary-fg: white;
--secondary: hsl(190 70% 38%);
--secondary-fg: white;
--success: hsl(150 58% 34%);
--success-fg: white;
--warning: hsl(42 92% 52%);
--warning-fg: hsl(35 35% 10%);
--danger: hsl(355 72% 52%);
--danger-fg: white;
--neutral: hsl(250 8% 42%);
--neutral-fg: white;
--surface: hsl(260 45% 98%);
--surface-raised: white;
--surface-subtle: hsl(260 35% 94%);
--surface-solid: hsl(260 28% 16%);
--text: hsl(260 24% 14%);
--text-muted: hsl(260 10% 42%);
--text-subtle: hsl(260 8% 56%);
--border: hsl(260 24% 84%);
--focus: var(--primary);
--focus-ring: hsl(260 70% 54% / 0.22);
--hover-overlay: hsl(260 30% 10% / 0.04);
--soft-bg-mix: 84%;
--soft-border-mix: 58%;
--radius: 0.625rem;
--radius-sm: 0.3125rem;
--radius-lg: 0.875rem;
}
Without data-theme, the default theme advertises color-scheme: light dark and follows the user's OS preference in browsers that support light-dark(). Dark themes should set color-scheme: dark. Light themes should set color-scheme: light. Browsers without light-dark() receive the light fallback. Because the native select chevron is an SVG background image and cannot inherit currentColor, the select hands the arrow back to the browser under prefers-contrast: more (same treatment as forced-colors: active) instead of shipping a recolored chevron per theme — one native fallback covers every theme without a high-contrast icon variant to maintain. In forced-colors: active, the default theme maps the public color tokens to system colors (Canvas, CanvasText, ButtonText, Highlight, and HighlightText) and removes decorative shadows. Components should inherit that token mode by default; keep local forced-color rules only for custom control geometry, native bar parts, disabled states, or selected states that would otherwise be communicated only by background color.