Exporting Color Tokens: Tailwind, CSS, JSON
On this page
- What you'll learn
- What color design tokens are
- How to name tokens
- Primitive tokens
- Semantic tokens
- The main token formats
- Tailwind config
- CSS variables
- JSON
- SCSS
- Exporting tokens from Zepixo
- Generate the scales
- Pick a format and export
- Using tokens in code
- CSS variables
- Tailwind
- JSON in JavaScript
- Tokens and theming
- Keeping tokens in sync
- Ban raw hex in components
- Re-export when the palette changes
- Version your tokens
- Frequently asked questions
- What is a color design token?
- What is the difference between primitive and semantic tokens?
- Which token format should I use?
- How do tokens enable dark mode?
- How do I export tokens from Zepixo?
- How do I keep tokens from drifting?
Color design tokens are the bridge between a palette and a codebase. A token is a named color, like color-text-primary, that points to a value, like #1e293b. Instead of pasting raw hex codes all over your app, you reference the name. Change the value once, and every place that uses the token updates. That single idea keeps a color system consistent and easy to evolve.
This guide is for designers and developers who have a palette and now need to ship it as code. I will explain what tokens are, how to name them so they scale, the main formats with a comparison table, how to export from Zepixo, and how to use the tokens in real projects. By the end you will move colors from your palette into Tailwind, CSS variables, JSON, or SCSS with confidence.
What you'll learn
- What design tokens are and why they beat raw hex
- How to name tokens with a layered system
- The main token formats and when to use each
- How to export tokens from Zepixo
- How to wire tokens into Tailwind, CSS, and JS
What color design tokens are
A design token is a name-value pair that stores a design decision. For color, the name describes a role or a step, and the value is the actual color. The token is the single source of truth, and your code points at it rather than at a hardcoded color.
The payoff is consistency and speed. When a designer tweaks the brand color, you update one token and the whole product follows. There is no hunting through files for stray hex codes. The same token can also hold a light value and a dark value, which makes theming a swap instead of a rewrite.
How to name tokens
Naming is where token systems live or die. Good names are predictable, so anyone can guess the token they need. The most robust approach uses two layers, primitive and semantic.
Primitive tokens
Primitive tokens name raw values by hue and step, with no meaning attached. Think indigo-500 or slate-900. They are the full ladder of every color, the raw material. You rarely use these directly in components.
Semantic tokens
Semantic tokens name a job, and they point at a primitive. Think color-text-primary or color-surface, which might point at slate-900 and white. These are what you actually use in code, because they carry meaning and survive a theme change.
The split is powerful. When dark mode arrives, color-surface points at slate-900 instead of white, and every component follows without edits. The component asked for the surface, not for a specific gray. This is the heart of a maintainable system.
| Layer | Example name | Points at | Used in components |
|---|---|---|---|
| Primitive | indigo-500 | #5b5bd6 | Rarely |
| Primitive | slate-900 | #0f172a | Rarely |
| Semantic | color-brand | indigo-500 | Yes |
| Semantic | color-text-primary | slate-900 | Yes |
| Semantic | color-surface | white or slate-900 | Yes |
Keep names lowercase with dashes, grouped by category. A predictable pattern like color-{role}-{variant} scales to hundreds of tokens without chaos. Our accessible color system guide covers how the roles map to contrast.
The main token formats
The same tokens can live in several formats, one per part of your stack. Here are the four you will meet most, and what each is best at.
| Format | Looks like | Best for |
|---|---|---|
| Tailwind config | theme.colors.brand | Tailwind projects, utility classes |
| CSS variables | --color-brand | Any site, runtime theming |
| JSON | { "color-brand": "#5b5bd6" } | Tooling, cross-platform, native |
| SCSS | $color-brand | Sass codebases, build-time |
Tailwind config
Tailwind reads your colors from its config and generates utility classes like bg-brand or text-brand-700. Tailwind v4 ships colors in OKLCH by default, which keeps scales even. This is the smoothest path if you already use Tailwind. See the Tailwind colors docs.
CSS variables
CSS custom properties, the --color-brand syntax, work in any project with no build step. They are the only format that can change at runtime, which is what makes them ideal for theme switching. A media query or a class on the body can swap the whole palette.
JSON
JSON is the universal, tool-friendly format. It carries no opinion about your stack, so build tools, native apps, and design tools can all read it. It is the common interchange format behind the Design Tokens standard.
SCSS
SCSS variables suit codebases already using Sass. They resolve at build time, so they are fast but cannot change at runtime. If your project compiles Sass, exporting SCSS keeps the tokens native to your workflow.
Exporting tokens from Zepixo
The Zepixo Colors workspace is built to hand off real tokens, not just swatches. You generate each role as a 50 to 950 OKLCH scale, then export the whole system in the format your stack uses.
Generate the scales
Set your primary, secondary, accent, and functional roles, and let the workspace build each as an even OKLCH scale. Lock any shade you want to keep fixed, and check the 11 by 11 contrast grid so the pairings pass. This is the palette your tokens will carry.
Pick a format and export
From the export panel, choose Tailwind, CSS variables, JSON, or SCSS. The workspace writes the tokens with consistent names and the right syntax for that format. You copy the output or download the file and drop it into your project.
Ready to export? Open the Zepixo Colors workspace, build your roles as OKLCH scales, and export tokens in Tailwind, CSS, JSON, or SCSS. The export reference walks through each format.
Using tokens in code
Exporting is only half the job. The other half is wiring the tokens into your project so components reference them. Here is how each format lands in real code.
CSS variables
Declare the tokens on the root, then reference them anywhere. Swapping a theme is just overriding the same variables under a selector.
:root {
--color-surface: #ffffff;
--color-text-primary: #1e293b;
--color-brand: #5b5bd6;
}
[data-theme="dark"] {
--color-surface: #0f172a;
--color-text-primary: #e2e8f0;
--color-brand: #a5b4fc;
}
.button {
background: var(--color-brand);
color: #ffffff;
}Tailwind
Map your tokens in the config, then use the generated utility classes in markup.
/* tailwind config */
theme: {
colors: {
brand: { 500: "#5b5bd6", 700: "#4338ca" },
surface: "#ffffff",
}
}
<button class="bg-brand-500 text-white">Save</button>JSON in JavaScript
Import the JSON and read tokens by name in components or a theme object.
import tokens from "./tokens.json";
const style = {
background: tokens["color-surface"],
color: tokens["color-text-primary"],
};The pattern is the same in every format. Components ask for a named token, never a raw hex. That indirection is what lets you restyle the whole app from one place. For the official model, see the MDN custom properties reference.
Tokens and theming
Theming is the clearest payoff of semantic tokens. Because a component asks for color-surface, not for white, you can point that token at a different value per theme and the component just follows.
Define each theme as a set of token values. The light theme maps color-surface to white, and the dark theme maps it to a deep slate. The structure is identical, only the values change. This is why dark mode is a swap, not a rewrite, when tokens are in place.
| Token | Light value | Dark value |
|---|---|---|
| color-surface | #ffffff | #0f172a |
| color-text-primary | #1e293b | #e2e8f0 |
| color-brand | #5b5bd6 | #a5b4fc |
For the full dark side of this, see our dark mode color palette guide. The tokens are the mechanism, and the dark palette is the content you pour into them.
Keeping tokens in sync
Tokens only help if they stay the single source of truth. The risk is drift, where someone pastes a raw hex into a component and the token no longer reflects reality. A few habits keep the system honest.
Ban raw hex in components
Make a rule that components never contain a hardcoded color. If a value is not a token, it does not belong. A linter can flag stray hex codes so they never slip in. This one rule preserves everything tokens give you.
Re-export when the palette changes
When a designer updates the palette in Zepixo, re-export and replace the token file. Because everything points at the tokens, the change ripples through automatically. The export is the handoff, and re-exporting keeps design and code aligned.
Version your tokens
Commit the token file to your repo and treat changes like any code change, with review. A diff on the token file shows exactly which colors moved. This makes color changes reviewable and reversible, which large teams need.
Frequently asked questions
What is a color design token?
It is a named color that points to a value, like color-brand pointing at #5b5bd6. Code references the name instead of the raw hex, so changing the value once updates everywhere. Tokens are the single source of truth for a color system.
What is the difference between primitive and semantic tokens?
Primitive tokens name raw values by hue and step, like indigo-500, with no meaning. Semantic tokens name a job, like color-text-primary, and point at a primitive. Components use semantic tokens, which is what makes theming a simple value swap.
Which token format should I use?
Use Tailwind config for Tailwind projects, CSS variables for any site that needs runtime theming, JSON for tooling and cross-platform use, and SCSS for Sass codebases. Many teams export several formats from one source palette.
How do tokens enable dark mode?
A semantic token like color-surface can hold a light value and a dark value. Components ask for the token, so swapping the theme repoints the token and every component follows. No component edits are needed for the theme change.
How do I export tokens from Zepixo?
Build your roles as OKLCH scales in the Colors workspace, check the contrast grid, then open the export panel. Choose Tailwind, CSS variables, JSON, or SCSS, and copy or download the generated tokens to drop into your project.
How do I keep tokens from drifting?
Forbid raw hex in components so every color is a token, and use a linter to catch strays. Re-export and replace the token file whenever the palette changes, and commit the file so color changes are reviewed like any code.
Name tokens in two layers, export the format your stack needs, ban raw hex, and re-export on changes. Do that and your colors will stay consistent from design to production. You have got this.
Shaheer Malik
Founder of Zepixo — building the whole brand studio in one tab. Try Zepixo →