Theming with tokens
Use the broadest token that matches the design decision.
Before writing any of this, check whether a shipped preset already gets you there — adopting one is a single import. Reach for the tokens below to retune a preset, or to build a theme none of them cover.
Prefer to see it before you write it? The Theme Studio tunes these same tokens live on a full product surface, then hands the result back as CSS, as an agent prompt, or as a shareable link.
| Need | Use |
|---|---|
| Replace a palette or scale | Primitive token |
| Change a system-wide purpose | Semantic token |
| Change color and emphasis | Variant roles |
| Make one component intentionally differ | Component token |
Start with semantic roles
:root {
--manti-bg: light-dark(#fafafb, #0c0c10);
--manti-surface: light-dark(#ffffff, #15151b);
--manti-surface-raised: light-dark(#ffffff, #1b1b22);
--manti-text: light-dark(#16161a, #f4f4f6);
--manti-text-muted: light-dark(#5c5c66, #b6b6c0);
--manti-border: light-dark(#e6e6ea, #2a2a33);
--manti-radius-factor: 0.8;
--manti-duration-base: 180ms;
}Keep theme-aware colors in light-dark(light, dark) form.
Use variants for color
Remap a built-in variant on the whole app or within a subtree:
.marketing [data-variant='primary'] {
--variant-solid: var(--manti-blue-9);
--variant-solid-hover: var(--manti-blue-10);
--variant-ring: var(--manti-blue-8);
}See Color & variants for the full role list.
Use component tokens for exceptions
:root {
--manti-button-radius: var(--manti-radius-full);
}If the same override appears on several components, move it to a semantic token
instead. Do not override private --_* variables.
Retune a size step
sm | md | lg is one shared rhythm. A control and the surface it opens resolve
the same --manti-size-* channel, so a sm Select opens a sm listbox and a
lg Menu lays out lg rows. Popups are portalled, so each adapter re-stamps
data-size on its positioner rather than relying on inheritance.
Retune a step once and every control and popup on it follows:
[data-size='sm'] {
--manti-size-item-padding-y: 0.125rem;
--manti-size-text: 0.8125rem;
}The channel carries text, text-sub, icon, control-height,
control-padding-x, panel-padding, panel-gap, item-padding-y,
item-padding-x, item-gap, item-radius, and cell. Every component token
above defaults to one of them, so a per-component override still wins.
Continue to plain CSS for anatomy selectors or Tailwind for utility integration.
Last updated