Customizing

The two override strategies, CSS layer override and JSON plus build, and when each one is the right tool.

There are two ways to change what this package produces. Pick by how deep the change goes, not by preference.

NeedApproach
Change the brand, the typography, a handful of tokensCSS @layer tokens
Add a few project-specific tokensCSS @layer tokens
Redefine the primitive palette entirelyJSON plus build
Add many project tokens, or generate other formatsJSON plus build

1. CSS override

Every token lives in @layer tokens, the lowest-priority layer in the recommended order. Any @layer tokens block imported after this package wins on source order, with no specificity tricks required.

@import '@uncinq/design-tokens';

@layer tokens {
  :root {
    --color-brand:        var(--color-violet-600);
    --color-brand-hover:  var(--color-violet-700);
    --color-brand-muted:  var(--color-violet-100);
    --color-brand-strong: var(--color-violet-900);
    --font-family-sans:   'Inter', system-ui, sans-serif;
  }
}

This covers most cases. Note that you are overriding the semantic layer while still referencing the primitive layer, which is exactly what the two-layer split is for: the palette stays intact and you only restate the intent.

Three things worth knowing:

Override the semantic token, not the component token, when you want the change to propagate. Setting --color-brand moves every component that reads it. Setting --btn-color-background moves only buttons.

Derived tokens follow automatically. --color-accent aliases --color-brand, and --color-text-muted derives from --color-text, so overriding the base moves the derivations too. Check Colors before overriding a derived token by hand, because doing so breaks the link.

The layer order must already be declared. If @layer tokens has not been named before the first import, the cascade fixes its position at that first import and your override may not land where you expect. See cascade layers.

2. JSON plus build

The package exports its raw DTCG sources under ./tokens/*. A consuming project can feed them into its own Style Dictionary config alongside its own token files.

// style-dictionary.config.js, in the consuming project
export default {
  usesDtcg: true,
  source: [
    'node_modules/@uncinq/design-tokens/tokens/**/*.json',
    'tokens/**/*.json', // project tokens, extending or overriding the package
  ],
  // ...
};

A project token file that defines the same path as a package token overrides it during the build. New paths are additive.

Use this approach to:

  • Redefine the primitive palette entirely, for a different brand hue or a different scale
  • Add semantic tokens that do not exist in the package
  • Generate output formats the package does not ship, such as JS, SCSS or JSON

That last point is the common reason to reach for it. This package emits CSS only, on purpose: CSS custom properties are the one format that works unchanged in Hugo, Symfony, Shopify and a plain HTML page. A project that needs the same values inside JavaScript should generate that itself from the same sources, so the two outputs cannot drift.

What not to do

Do not edit dist/. It is generated by npm run build and overwritten on every build. The header of each generated file says so.

Do not fork to change one color. The CSS override above exists precisely so that a brand change does not require a fork. A fork inherits the maintenance of 19 hues and 660 tokens for a single line of difference.

Do not override a primitive to change a semantic meaning. Redefining --color-gray-100 to make one muted background darker will move every other token referencing gray-100, most of which you have not thought about. Override the semantic token instead.