Design Tokens and Variables in shadcncraft
How design tokens are organized into collections changed in v3 of the kit. Not sure which version you have? See how to tell which version you're using.
Collections
v3 organizes every design token into three variable collections. They reference each other in a clear chain: components point at Mode, Mode resolves through Style, and Style is built on Tailwind primitives.
1. Tailwind
A single-mode collection of raw, utility-first primitives that mirror Tailwind's scale. These are the lowest-level values in the system. Nothing references anything beneath them. It replaces the Primitives collection from v2.
| Group | Usage |
|---|---|
spacing | The Tailwind spacing scale: padding, gap and margin values |
border-radius | Corner-radius primitives |
border-width | Stroke-thickness primitives |
font | Type-scale primitives: font size, weight and line height |
width | Width primitives for components and elements |
max-width | Minimum and maximum width constraints |
height | Height primitives for components and elements |
opacity | Transparency steps |
colors | The raw color palette that the Style collection resolves from |
ring-width | Focus-ring thickness primitives |
shadows | Shadow primitives: the raw values behind each shadow |
pro | Primitives specific to the Pro kit |
meta | Kit metadata, such as the library version |
2. Style
Style is the theming heart of v3. It is a multi-mode collection where each mode is a complete, named visual style: color palette, radii, shadows, spacing rhythm, typography and icon set all defined together. shadcncraft ships eight styles out of the box:
- Nova
- Vega
- Maia
- Lyra
- Mira
- Luma
- Sera
- Rhea
Switching the active Style mode re-themes the entire library in one move. The Style collection takes over the role the Theme collection played in v2.
There's no need to learn every variable in here. Work at the group level. Each group is summarized below:
| Group | Usage |
|---|---|
color | Per-style color resolutions for light and dark mode |
icon-library | Boolean toggles for the active icon set (Lucide, Remix, Phosphor, Tabler, Huge) |
font | The sans, serif, mono and heading typefaces |
pro | The Pro spacing scale used for padding, gaps and margins across blocks. See the pro spacing scale |
radius | The semantic radius scale (radius/sm … radius/4xl), resolved per style |
shadow | Per-style shadow definitions |
text | The per-style type scale: font size and line height for each step (text-xs … text-9xl) |
focus-ring | The focus-ring token, resolved per style |
component | Per-component tokens such as component/card/radius or component/input/bg. See component variables |
The pro spacing scale
pro/space/* is a semantic spacing scale, and it is the group people ask about most, so it gets its own note.
Each step aliases a raw step from the Tailwind collection, and which step it aliases changes per style. pro/space/4 resolves to Tailwind spacing/3 (12px) in Nova and Tailwind spacing/4 (16px) in Vega. That is the whole idea: spacing rhythm re-themes when you switch the Style mode, exactly like color, radius and type already do.
Vega, Maia and Luma map one-to-one, so read the step number as "the Tailwind step this would be in a default shadcn/ui layout". The compact styles step down from there and Sera steps up.
| Step | Nova | Vega | Maia | Lyra | Mira | Luma | Sera | Rhea |
|---|---|---|---|---|---|---|---|---|
pro/space/0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 0.5 | 1 | 0.5 |
pro/space/1 | 1 | 1 | 1 | 1 | 1 | 1 | 1.5 | 1 |
pro/space/1.5 | 1 | 1.5 | 1.5 | 1 | 1 | 1.5 | 2 | 1 |
pro/space/2 | 1.5 | 2 | 2 | 1.5 | 1.5 | 2 | 3 | 1.5 |
pro/space/2.5 | 2 | 2.5 | 2.5 | 2 | 2 | 2.5 | 3.5 | 2 |
pro/space/3 | 2.5 | 3 | 3 | 2 | 2.5 | 3 | 4 | 2.5 |
pro/space/4 | 3 | 4 | 4 | 3 | 3 | 4 | 5 | 3 |
pro/space/5 | 4 | 5 | 5 | 4 | 4 | 5 | 6 | 4 |
pro/space/6 | 5 | 6 | 6 | 5 | 5 | 6 | 8 | 5 |
pro/space/8 | 6 | 8 | 8 | 6 | 6 | 8 | 10 | 6 |
pro/space/9 | 7 | 9 | 9 | 7 | 7 | 9 | 10 | 7 |
pro/space/10 | 8 | 10 | 10 | 8 | 8 | 10 | 12 | 8 |
pro/space/12 | 10 | 12 | 12 | 10 | 10 | 12 | 16 | 10 |
pro/space/16 | 12 | 16 | 16 | 12 | 12 | 16 | 20 | 12 |
pro/space/20 | 16 | 20 | 20 | 16 | 16 | 20 | 24 | 16 |
Cells are Tailwind spacing steps, where step n is n × 4px. So Sera's pro/space/4 is step 5, or 20px.
Where to use it. Bind it wherever a layout value should breathe differently per style:
- Auto-layout gap and padding on blocks, sections and page compositions
- Vertical rhythm between stacked elements
- Item spacing inside a repeated list or grid
Where not to use it:
- Anything that is not spacing. Color, borders, shadows and fills belong to the other groups. There is no
protoken for them by design. - Component surfaces that already carry their own tokens. A Card's padding comes from
component/card/*, not frompro/space/*. Bind the component token instead. - Values that should never move. A 1px hairline offset, an icon nudge, an optical tweak. Type those directly.
It is optional. This is the important part: you do not have to use it. Typing a raw Tailwind spacing value, or a plain number, is a perfectly valid way to build in the kit and nothing downstream breaks. The only thing you give up is per-style flex, so your spacing stays put when the Style mode changes while everything around it re-themes.
If you are designing against a single style, reach for pro/space/* when it is convenient and skip it when it is not. If you are building something that has to look right in all eight styles, use it consistently.
How it lands in code. Registry blocks author these as --sc-space-* references and the build resolves them per style, so installed components ship plain Tailwind utilities such as p-3 or gap-1.5. The token never reaches your project's CSS. That means a design bound to pro/space/4 and the code you install stay in step without you configuring anything.
Component variables
component/<component>/* is the other group that gets asked about, usually as "do these come from shadcn, and do I need to add classes in code to match?"
Where sizing lives in code. In shadcn/ui a component's sizing is written as Tailwind classes on the component itself, and those classes differ across the eight styles. Install Tabs in Nova and the list is h-8. Install it in Vega and the list is h-9. The only variables in code are the global tokens in globals.css: colors, radius, spacing and fonts.
Why Figma needs a variable for it. Figma has no equivalent of a class that changes with the active style. A value is either a variable, which can carry one value per mode, or a typed number, which stays put. So for every property that differs per style, the kit defines a component/<component>/* variable in the Style collection with one value per style mode. The values are derived from shadcn's source for each style, so what you see in Figma is what shadcn renders.
A worked example. The Tabs list height differs per style, so the kit has component/tabs/list/height-horizontal. Switch the Style mode from Nova to Vega and the list grows from 32px to 36px, because that is what the Nova and Vega Tabs components render. The same pattern covers padding, gap, radius and per-variant colors on every component that varies.
What this means in code. Install the component with the shadcn CLI in the style you designed in, set your tokens in globals.css, and it renders with the values you saw in Figma. No extra classes. The component variables stay in Figma and the installed component already carries the matching classes. The one case that needs a code change is a deliberate override: if you edit a component variable in Figma, say a taller Tabs list, the matching change is a class edit in that component's .tsx.
3. Mode
Mode is the collection you apply to elements. It has two modes, Light and Dark, and its variables alias into the Style collection. A component bound to a Mode color automatically reflects whichever Style is active and whether the page is in light or dark mode.
| Group | Usage |
|---|---|
Root | The core UI colors (primary, background, border, muted, …) |
custom | Figma-specific tokens used to reproduce the shadcn/ui look |
chart | Colors used for charts |
sidebar | Colors specific to the sidebar component |
Color variable usage guide
The meaning of each color is the same across kit versions. Apply these from the Mode collection. Swatches show shadcn/ui's default light theme, which the kit's default style matches.
| Swatch | Color | Usage |
|---|---|---|
primary | Define the color palette used for your theme | |
primary-foreground | For elements on top of primary | |
secondary | Your secondary brand color | |
secondary-foreground | For elements on top of secondary | |
accent | Highlight color for active or focused elements | |
accent-foreground | For elements on top of accent | |
background | Main application background color | |
foreground | For elements on top of background | |
card | Background color for cards | |
card-foreground | For elements on top of card | |
popover | Background color for things like select menus | |
popover-foreground | For elements on top of popover | |
muted | Subtle background for elements requiring less attention | |
muted-foreground | For elements on top of muted | |
destructive | For errors and destructive actions like delete | |
destructive-foreground | For elements on top of destructive | |
border | Main border color | |
input | Border color for form input elements | |
ring | Helps define the focus indicator | |
custom/focus | The soft outer focus ring on focused elements like buttons | |
custom/destructive-focus | The soft outer focus ring on focused elements like destructive buttons | |
bg-input-30 | Used for the background of elements like input to increase contrast in dark mode. More info here | |
bg-input-50 | Used in the backgrounds of elements on hover like Combobox | |
bg-input-80 | Used for input element background like Switch |
Tokens like custom/focus and bg-input-* are shadcncraft additions that reproduce shadcn/ui's look. They have no direct shadcn CSS token, so no swatch is shown.
Best practices
- Apply Mode variables to elements. Never apply Style or Tailwind variables directly.
- Theme by switching or editing the Style collection, not by editing individual component colors.
- Reach for Tailwind primitives only for raw spacing, sizing and radius values.
- Use
pro/space/*for layout spacing that should change per style, and raw values for spacing that should not. Both are fine. - Use variables instead of hard-coded values so designs stay aligned with shadcn/ui and translate cleanly to Tailwind CSS.
