Guide

Design tokens from JSON to CSS

For whoever maintains a small site or app: at the end every design decision is in one file, the CSS is generated from it, and a test fails when someone writes a colour by hand.

Updated
·

Before you start

  • A stylesheet in which colours, spacing and fonts recur as raw values.

  • A script step that can generate a file and check it in the build.

  • A test runner that can read the stylesheets.

Steps

  1. Put the decisions in one file, in tiers

    The token file holds every decision: colours, fonts, sizes, spacing, radii, focus and motion. Primitive values sit in one tier, roles (text, surface, border, action) refer to them, and components refer to the roles. A component never uses a primitive directly.

    Check: Every value in the file is either a primitive or a reference.

  2. Generate the custom properties and check for drift

    A script compiles the file into custom properties and keeps the references as var() references, so the tiers stay visible in the browser's tools. The same script in check mode fails when the generated file differs from the source; the check is part of the build.

    Check: The generated file cannot be edited by hand unnoticed.

  3. Forbid raw values outside the generated file

    A test reads every stylesheet and fails when a colour is written as a value anywhere but the generated file, or when a custom property in use is undefined. The same test limits media queries to the tokens' breakpoints.

    Check: A new colour needs a change to the token file.

  4. Declare the contrast pairs and test them

    The file lists the pairs of text and background and the focus ring against its background, each with the ratio it must meet. A test computes the ratios and fails when a change makes a pair unreadable.

    Check: A colour change cannot break readability silently.

  5. Let layers decide the order

    The cascade layers are declared once: tokens, base, layout, components, utilities, overrides. A utility always beats a component and a component always beats the base, whatever the selectors look like, so the specificity race ends.

    Check: A fix does not need a more specific selector.

  6. Vendor another system's tokens with provenance

    When the look belongs to another product, its token file is copied verbatim, and next to it the source, the version and the commit are recorded, along with every deliberate deviation. The own file holds only references into it. Values change at the source and are vendored again.

    Check: Every deviation from the source is recorded.

When not to use this

  • A single page that will not be maintained: custom properties at the top of the stylesheet are enough.

  • The design system already ships as a package with its own tokens and checks: use it, do not copy it.

  • Nobody runs the check: the generated file drifts from its source within a week.

Where it comes from

This site is built this way: the tokens are references into the vendored tokens of the Hintapiste.fi design system, the custom properties are generated, and the tests check drift, raw colours, undefined properties and the contrast pairs on every build.