Theming
LatticeUI is themed entirely through CSS custom properties compiled from W3C design tokens. There is no theme object, no provider, and no runtime cost - overriding a theme is just CSS.
The token layers
- Reference tokens (
--ts-color-*,--ts-space-*, ...) - raw palette and scales. Rarely overridden. - Semantic tokens (
--ts-bg-canvas,--ts-accent-default,--ts-fg-muted, ...) - what components actually consume. Override these to re-theme everything at once. - Component tokens (
--btn-bg,--alert-accent, ...) - per-component knobs documented in each component's Styling section.
Change the brand color
One rule re-themes every button, badge, focus ring, and accent in the system:
:root {
--ts-accent-default: oklch(0.65 0.2 300); /* purple instead of teal */
--ts-accent-emphasis: oklch(0.58 0.21 300);
--ts-accent-fg: oklch(0.78 0.16 300);
--ts-accent-subtle: oklch(0.3 0.08 300 / 0.35);
}Dark / light mode
Themes are keyed off data-theme on <html>. Both themes ship in tokens.css; switching is instant and SSR-safe.
<html data-theme="light"> <!-- or "dark" (default) -->Restyle a single component
Components expose stable data-scope/data-part attributes - a versioned styling API. Because all library CSS sits in @layer latticeui, your unlayered CSS always wins. No specificity wars, no !important:
/* square buttons, app-wide */
[data-scope="button"][data-part="root"] {
border-radius: 0;
}
/* or tweak one component token */
[data-scope="button"][data-part="root"][data-variant="solid"] {
--btn-bg: var(--ts-success-default);
}Scoped themes
Because everything is CSS variables, you can theme a subtree - useful for marketing sections or embedded widgets:
.promo-section {
--ts-accent-default: #f59e0b;
--ts-radius-md: 2px;
}Build your own token set
The source of truth is W3C design-token JSON in latticeui-tokens. Fork the JSON, run the build script, and you get a complete tokens.css plus typed TypeScript maps for your own brand.