MOESS

· updated · Dieter Möss

Tokens instead of guessed color values

Hard-coded color values and pixel values pose a particular risk in frontend projects. As soon as an agent writes #ff0000 or padding: 14px directly into a component, the system starts to drift apart.

Models behave this way because they have encountered this pattern frequently. The instruction “Build a red delete button” therefore quickly leads to a bg-red-500, even if your own token has a different name.

Three tiers

  1. Primitive tokens are raw values: color.red.600 = #da1e28. Components never access them directly.
  2. Semantic tokens name an intent: color.surface.danger references the raw value and contains the rule for what it's meant for.
  3. Component tokens bind the intent to a specific place: button.danger.background.

This three-way split is common practice; the names serve as examples.

Tailwind v4: turning off the default colors

In Tailwind CSS v4, you can remove the built-in colors and allow only your own. Both are described in the documentation on theme variables:

:root {
  --surface: #ffffff;
  --danger: #da1e28;
}

@theme {
  /* remove all of Tailwind's default colors */
  --color-*: initial;
}

@theme inline {
  --color-surface: var(--surface);
  --color-danger: var(--danger);
}

I verified this with Tailwind 4.3. Afterward, bg-surface and bg-danger are available, while bg-blue-500 no longer is. The split into @theme and @theme inline isn't spelled out like this in the documentation; there, the two parts are described separately.

Contrary to what one might expect, the build doesn't fail because of this. The class merely produces no rule, and the element stays uncolored. For such cases to be noticed, you also need a linter that reports unknown classes, such as eslint-plugin-better-tailwindcss with the rule no-unknown-classes (up to version 3 it was called no-unregistered-classes).

Since the classes point to variables, a dark color scheme can be implemented as a side effect by overriding the variables in one place.

Limits of the lock

The lock removes only the default palette. Tailwind still generates arbitrary values in square brackets, so bg-[#ff0000] or p-[14px] work just as before, and so does style="color:#f00". A correct token in the wrong place won't be noticed anyway. Both have to be caught by a check in the pipeline, such as a linter that prohibits classes containing [#. That's the topic of the next part.

From the series “Design Systems and AI”. Previous: Contracts instead of essays: describing components in a machine-readable way. Next: Who checks the agents' code?.

Design TokensTailwind CSSAI Agents

Want to build a digital product with a system?

Start a project