Skip to content
Design Tokens

Set up design tokens in Tailwind CSS

How to anchor design tokens in Tailwind CSS: colors, spacing and radii as CSS variables, made usable through the theme block, plus theme switching.

9 min readUpdated: 12 July 2026
Design tokensTailwindDark mode
--color-primary01
Series 04
Light that stays all day
Six lamps from one workshop in Utrecht.
See the rangeShowroom

Design tokens are the named base values of your design: colors, spacing, font sizes and radii. In Tailwind CSS you can store them as CSS variables and use them directly as utility classes. This guide shows how to anchor tokens cleanly so your theme stays controllable in one place.

The short version
  • Tokens are named decisions. Not blue, but primary.
  • In Tailwind v4 they live as CSS variables in the theme and therefore apply to utilities and your own CSS at once.
  • Few roles beat many values. Three greys you understand are better than twelve you guess at.
  • With tokens a dark mode is a swap of values, not a second set of classes.
01

Why tokens instead of fixed values

When color values and spacing are hard-wired throughout the project, every adjustment turns into a search. A token gathers the value under a meaningful name, such as color-primary or space-4. A change at the source then takes effect everywhere.

Names also create a shared language. Design and development talk about primary and surface instead of random hex numbers. That reduces misunderstandings and keeps the interface consistent across many components.

02

Define tokens as CSS variables

The natural place for tokens are CSS variables in the :root block of your stylesheet file. There you set values like --color-primary, --radius-md or --space-4. Because they are real CSS variables, they are available everywhere and can be changed at runtime.

Keep the names flat and predictable. A scale like --space-1 to --space-8 or --color-fg and --color-bg is easier to remember than made-up labels. This order pays off as soon as the project grows.

HandyAa20px
TabletAa30px
DesktopAa42px
A scale instead of loose values. Three steps you remember beat twelve you look up.
:root {  --blue-600: #1f5eff;  --slate-900: #0f172a;    --color-primary: var(--blue-600);   --color-text: var(--slate-900);   --radius-md: 8px;}
Raw values on top, roles below. Two levels, one file.
03

Make tokens available in Tailwind

In Tailwind CSS v4 you configure the theme directly in the stylesheet through the theme block. There you point at your variables, for example color-primary to var(--color-primary). From this entry Tailwind automatically generates fitting utilities like bg-primary or text-primary.

This keeps a single source of truth. Your components use the utility classes, these reach for the tokens and the tokens live centrally in the variables. Change a value there and the adjustment carries through all classes.

01PageOne URL, rendered.
02Raw valuesEverything in the stylesheet.
03RolesMerge them and name them.
04VariablesOnly here they are tokens.

From the variable to the class in the component. Only the first station is touched when something changes.

@theme {   --color-primary: var(--color-primary);   --color-text: var(--color-text);} /* daraus entstehen bg-primary, text-primary, border-primary */
Tailwind turns every entry in the theme block into utilities.
04

Semantic instead of raw names

It is worth separating two layers. On the lower layer are raw values like blue-500 with their color value. On the upper layer are semantic tokens like primary that point to a raw value. Components use only the semantic layer.

This small detour makes your system flexible. Want to change the brand color, you only change what primary points to. No part has to be touched, because none is bound directly to a raw value.

Read out16 colours, many nearly identical.
#1f5eff#1f5dfe#2060ff#0f172a#0f172b#111827#ffffff#fefefe#f8fafc#f7f9fb#e2e8f0#e3e8f1#64748b#65748a#94a3b8#1f5eff
KeptFour roles, each with one job.
  • primaryPrimary#1f5eff
  • surfaceSurface#f8fafc
  • textText#0f172a
  • borderBorder#e2e8f0

Left, the values a mid-sized site produces. Right, what belongs in a project as a role.

Names that state the colour
  • blue-500, blue-600, blue-light.
  • After a rebrand, green is suddenly called blue-500.
  • Nobody knows which of the two greys is for borders.
  • Dark mode needs a second set of names.
Names that state the job
  • primary, surface, border, text.
  • A rebrand only changes what primary points at.
  • border is border, whatever grey sits behind it.
  • Dark mode overrides the same four names.

Few roles beat many values.

A list of hex numbers is an inventory. It becomes a system only once every value has a job.

ColourFour roles instead of sixteen values.
TypographyOne scale, no one-offs.
SpacingA four pixel step is enough.
05

Switch themes through tokens

Because tokens are CSS variables, a dark mode becomes almost incidental. You override the same variables in a second context, for example under a data-theme attribute or a class on the root element. The utility classes stay unchanged.

The components know nothing about the active theme, they simply read the current variable values. That way you switch between light and dark without touching a single class in the parts.

:root { --color-surface: #ffffff; --color-text: #0f172a; }   [data-theme="dark"] {    --color-surface: #0f1115;    --color-text: #f4f5f7;  }
Same names, different values. The components notice nothing.
06

Maintain and document tokens

A token set is only as good as its upkeep. Keep the list short and remove values no one uses. Every extra token without a clear purpose makes the system heavier rather than richer.

A brief documentation helps the team. A section in the README or a DESIGN.md that lists colors, spacing and their meaning ensures new parts use the same values and the design stays consistent.

Keep the docs next to the valuesA DESIGN.md that sits in a different folder than the stylesheet is out of date after the third change. Write half a sentence per role as a comment right above the variable, then the explanation sits where someone reads it anyway.
07

Why token sets fail

A set of tokens is quickly created. Making it still true a year later is the actual work.

  1. Too many values. Twelve greys mean nobody knows which one is for what any more. Three with a job cover almost everything.
  2. Names that name the color. blue-500 does not survive a rebrand. Primary, surface, border and text do.
  3. Exceptions inside the component. A single hard coded #1f2937 is the spot where a dark mode breaks later.
The exception in the componentA single hard-coded #1f2937 in the middle of your code only shows up when someone switches on dark mode and a surface sits black on black. Search your source for hash signs before every theme change.

A token is a decision with a name. Without the name it is just a value.

08

Dark mode without a second set of classes

When colors live as tokens, a dark mode is a swap of values. You define the same names again under a selector, and everything using those names follows.

Two things you have to check yourself: images often need less contrast in the dark, and hard coded colors in individual components only show up there. Anyone working through tokens from the start has almost nothing to do when switching.

Share
Written by
Amelie RoesmannCreative directionLeonie RoesmannDesign engineering

We build websites and web apps at Systra Studios in Münster and put the building blocks from that work here. What you read comes from real projects, not from a brochure.

Systra Studios: web design from Münster

You know what matters.
The reading is the tool's job.

Enter a URL, get colours, typography and spacing. As a DESIGN.md for people or a tokens.json for your build.

  • Colours are checked against the rendered page.
  • Values close to each other get merged.
  • Output as markdown or JSON, both ready to copy.
Open Style Extractor
Result
  • primary#1f5eff
  • surface#f8fafc
  • text#0f172a
  • border#e2e8f0
TypographyAaInter · 16 / 20 / 28 / 40
FAQ

Frequently asked questions

Not in Tailwind v4. The theme lives in the stylesheet in the theme block, and that is also where your variables become utilities. You only need a config file for plugins or when migrating from v3.

Didn't find your question? We're happy to help.

Get in touch