Theming

Two token layers drive every component. Point them at your brand, pick a tint, radius and type, and the whole library follows, dark mode included.

Letrix UI components never hard-code a color. They reference tokens (CSS custom properties in two layers), so restyling the entire library means editing a handful of variables, not a thousand class names.

The two layers

Primitive scales, prefixed --lx-*, define what exists: brand, gray, error, warning and success, each from 25 to 950, plus the radius and font tokens. Semantic tokens (--bg-*, --text-* and --border-*) define what they are for: surfaces, text roles, borders. Components only use the semantic layer, which is what makes dark mode and rebranding automatic.

styles/letrix-tokens.css (excerpt)
Matches the customizer
:root {
  /* layer 1: primitive scales (--lx-*), rewritten by the customizer */
  --lx-brand-600: #1570EF;
  --lx-gray-200: #EAECF0;
  --lx-radius-md: 8px;
  --lx-font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;

  /* layer 2: semantic tokens, what components actually use */
  --bg-primary: #FFFFFF;
  --text-primary: var(--lx-gray-900);
  --border-primary: var(--lx-gray-300);
}

.dark {
  --bg-primary: var(--lx-gray-950);
  --text-primary: var(--lx-gray-50);
}

Make it your brand

Pick one of 17 brand presets, or paste your own hex and the ramp is generated in OKLCH. Add a gray tint (neutral, cool or warm), a radius scale from sharp to fully round, and a type family. The customizer sets the --lx-* variables directly on document.documentElement, and because every utility embeds a var() reference, every component updates live, both themes included, zero rebuilds. The block below is that theme as CSS — it follows the customizer as you change it, so what you copy is what you are looking at.

styles/letrix-tokens.css
Matches the customizer
:root {
  /* Brand ramp */
  --lx-brand-25: #F5FAFF;
  --lx-brand-50: #EFF8FF;
  --lx-brand-100: #D1E9FF;
  --lx-brand-200: #B2DDFF;
  --lx-brand-300: #84CAFF;
  --lx-brand-400: #53B1FD;
  --lx-brand-500: #2E90FA;
  --lx-brand-600: #1570EF;
  --lx-brand-700: #175CD3;
  --lx-brand-800: #1849A9;
  --lx-brand-900: #194185;
  --lx-brand-950: #102A56;

  /* Radius */
  --lx-radius-sm: 6px;
  --lx-radius-md: 8px;
  --lx-radius-lg: 12px;
  --lx-radius-xl: 16px;
  --lx-radius-2xl: 20px;

  /* Type */
  --lx-font-sans: 'Inter', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

Try it now. The customizer in this docs header re-themes every example on the page live (brand, tint, radius and type), so you can preview your brand before writing any code.

Dark mode

Add class="dark" to the root element and the semantic layer remaps: no second stylesheet, no duplicated components. You can also scope themes: wrap any subtree in .light or .dark and the nearest wrapper wins, which is how the finance example runs a dark sidebar against light content, and how every example frame here previews the other theme in isolation.

Rules that keep it consistent

Semantic first, scale second. No raw hex values in components. States ship with every recipe. The full conventions, written for humans and AI assistants, live at the bottom of the .