HomeJournalThis post

How I structure a design tokens starter

A starter model for primitives, semantic tokens, component tokens, CSS variables, and handoff documentation.

JP
JP Casabianca
Designer/Engineer · Bogotá

A useful design tokens starter should teach the system as much as it stores values. The goal is not to create a giant JSON file. The goal is to make product decisions portable between design and code.

When I structure a starter, I optimize for a new teammate opening it on a normal workday. They should be able to answer three questions quickly:

  1. Which layer should I use?
  2. How does this token reach CSS?
  3. What should I do when the token I need does not exist?
JSON Build CSS vars Docs A starter should make the path from decision to implementation visible.
Figure 1: Token starters are most useful when source values, generated output, and documentation are treated as one workflow.

Keep the starter small enough to understand

A starter is not the final system. It is the seed. If it begins with hundreds of tokens, nobody can tell which parts are essential.

Start with the minimum set that can build a realistic screen:

  • color primitives
  • semantic color roles
  • spacing scale
  • radius scale
  • type sizes
  • a few component aliases
  • light and dark mode examples

The starter should show the pattern, not exhaust every future need.

Use primitives as raw materials

The primitive file should be boring:

{
  "color": {
    "green": {
      "50": "#ecfdf5",
      "500": "#10b981",
      "900": "#064e3b"
    }
  },
  "space": {
    "1": "4px",
    "2": "8px",
    "3": "12px",
    "4": "16px"
  }
}

These values are materials. They should not know whether they are used in a button, a chart, or an alert.

Put product meaning in semantic tokens

Semantic tokens are the most important part of the starter because they teach the naming model.

{
  "color": {
    "bg": {
      "page": "{color.cream.50}",
      "surface": "{color.white}"
    },
    "text": {
      "default": "{color.green.950}",
      "muted": "{color.gray.600}"
    },
    "action": {
      "primary": {
        "bg": "{color.green.500}",
        "text": "{color.white}"
      }
    }
  }
}

This layer tells the team what jobs exist in the interface. It also makes redesign possible without rewriting every component.

Generate CSS variables

The starter should produce a practical output:

:root {
  --color-bg-page: #fbfaf4;
  --color-bg-surface: #ffffff;
  --color-text-default: #071812;
  --color-text-muted: #68736f;
  --color-action-primary-bg: #10b981;
}

Do not make engineers reverse-engineer the token pipeline. Show the input and output side by side.

Include a real example screen

A token starter without an example is too abstract. Include a small screen that uses the tokens: a dashboard card, a settings form, or a pricing block.

The example should demonstrate:

  • background and surface roles
  • text hierarchy
  • border roles
  • action color
  • spacing scale
  • dark mode
  • one component alias
PageSemantic roles

Background, surface, text, border, action.

ComponentLocal aliases

Button and input tokens map back to semantics.

ModeLight and dark

Same decisions, different resolved values.

Figure 2: A starter should prove that the token model can render a real interface, not only a swatch table.

Document contribution rules

The starter should explain what to do when a token is missing.

I like a short rule:

If the need is raw material, add a primitive. If the need describes product intent, add a semantic token. If the need only exists inside one component state, add a component token that aliases a semantic token when possible.

That rule prevents many one-off additions.

The adoption test

The starter is working when a new screen can be built without inventing new colors, mystery spacing, or unsupported typography.

It does not need to answer every future question. It needs to teach the team how answers should be created.

What to ship with the starter

A useful starter should include more than token JSON. I would ship:

  • source token files
  • generated CSS variables
  • a small HTML or React example
  • light and dark mode output
  • naming documentation
  • contribution rules
  • a short troubleshooting section

The troubleshooting section is underrated. It should answer questions like "what if I need a new color?", "what if a component needs a local state?", and "what if the Figma variable name does not match code yet?"

Keep the starter honest

Do not present the starter as a universal system. It is a starting point. The product will teach you where the model is too thin. A real form, table, pricing section, or dashboard will expose missing states faster than a swatch page.

That is why the starter should include an example screen. If the tokens cannot support one realistic interface, they are not ready to teach anyone else.

How I would use it in a real repo

In a real product repo, I would start by using the starter on one contained surface: a settings page, a billing card, or a small dashboard. I would wire the generated CSS variables into that surface and resist touching the rest of the app until the model survives one real workflow.

Then I would review every place the implementation needed a value that did not exist. Some gaps would become new semantic tokens. Some would reveal that the spacing scale is too thin. Some would show that a component token is justified. That review is where the starter turns from a template into a system.

The important habit is to let product work pressure-test the token model. Tokens created only in abstract tend to look clean and fail quietly. Tokens tested against real screens become less elegant and more useful.

What not to include yet

I would avoid animation tokens, complex elevation systems, chart palettes, and deeply nested component tokens in the first version unless the product already needs them. Those areas can be added later. A starter should leave room for growth without pretending the team already knows every future decision.

That is the difference between a token dump and a token starter. One stores values. The other teaches a system.