The W3C Design Token Community Group (DTCG) defines a standard interchange format for design tokens, so they can travel between tools (Figma, code, documentation) without loss of meaning.
@uncinq/design-tokens uses DTCG JSON as its source format. Style Dictionary v5 transforms those JSON files into CSS custom properties — see STYLE-DICTIONARY.md for the build pipeline. The DTCG spec informs the architecture (primitive → semantic → component, naming conventions, token types).
The DTCG spec defines tokens as JSON objects with reserved $-prefixed keys:
{
"color": {
"brand": {
"$value": "oklch(0.530 0.195 22.0)",
"$type": "color",
"$description": "Primary brand color — used for CTAs and highlights."
}
}
}Note on OKLCH: The DTCG
colortype accepts any valid CSS color value, includingoklch(…).@uncinq/design-tokensuses OKLCH throughout — perceptually uniform, wide-gamut, and natively supported in modern browsers.
| Key | Required | Description |
|---|---|---|
$value |
✅ | The token's value |
$type |
recommended | The token type (see below) |
$description |
optional | Human-readable documentation |
$extensions |
optional | Vendor-specific metadata (e.g. Figma) |
| Type | Example value | CSS usage |
|---|---|---|
color |
oklch(0.530 0.195 22.0) |
color, background-color |
dimension |
1rem, 4px |
width, padding, font-size |
fontFamily |
"system-ui, sans-serif" |
font-family |
fontWeight |
700 |
font-weight |
duration |
300ms |
transition-duration |
cubicBezier |
[0.165, 0.84, 0.44, 1] |
animation-timing-function |
number |
1.5 |
line-height, opacity |
string |
"uppercase" |
free-form text values |
strokeStyle |
"solid", "dashed" |
border-style |
| Type | Shape | CSS usage |
|---|---|---|
shadow |
{offsetX, offsetY, blur, spread, color} |
box-shadow |
border |
{width, style, color} |
border shorthand |
transition |
{duration, delay, timingFunction} |
transition shorthand |
typography |
{fontFamily, fontSize, fontWeight, letterSpacing, lineHeight} |
typography rules |
gradient |
{gradientType, stops[]} |
background: linear-gradient(…) |
→ Full type list: tr.designtokens.org/format/#types
Note on
clamp()values: DTCG has no nativefluidtype. Fluid tokens (--font-size-fluid-sm,--font-size-fluid-md,--spacing-fluid-*) use$type: "dimension"as the closest match — a documented gap in the spec.
CSS property names that are two words (kebab-case in CSS) are written as a single camelCase key — not as a nested group. The pathToKebab transform converts them back to kebab-case for the CSS output, so the result is identical either way.
| JSON key | CSS custom property |
|---|---|
"fontFamily" |
--btn-font-family |
"fontSize" |
--btn-font-size |
"fontStyle" |
--btn-font-style |
"fontWeight" |
--btn-font-weight |
"lineHeight" |
--btn-line-height |
"maxHeight" |
--btn-max-height |
"maxWidth" |
--btn-max-width |
"textAlign" |
--btn-text-align |
"textDecoration" |
--btn-text-decoration |
"textTransform" |
--btn-text-transform |
// ✅ correct
"btn": {
"fontSize": { "$value": "{fontSize.sm}", "$type": "dimension" },
"fontWeight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
}
// ❌ wrong
"btn": {
"font": {
"size": { "$value": "{fontSize.sm}", "$type": "dimension" },
"weight": { "$value": "{fontWeight.bold}", "$type": "fontWeight" }
}
}Exception — semantic namespaces: border, color, padding, margin, shadow used to group multiple sub-properties stay nested, because the group key itself is not a CSS property compound word.
// ✅ border as a namespace grouping multiple properties
"border": {
"radius": { "$value": "{radius.control}", "$type": "dimension" },
"width": { "$value": "{border.width.sm}", "$type": "dimension" }
}
// ✅ color as a semantic grouping
"color": {
"background": { "$value": "{color.background.default}", "$type": "color" },
"text": { "$value": "{color.text.default}", "$type": "color" }
}Sub-axes of padding and margin use CSS logical property names as sub-keys — not physical directions (x, y, top, bottom, left, right).
| Sub-key | CSS logical property | Physical equivalent |
|---|---|---|
"inline" |
padding-inline / margin-inline |
left + right |
"block" |
padding-block / margin-block |
top + bottom |
"inlineStart" |
padding-inline-start / margin-inline-start |
left (LTR) |
"inlineEnd" |
padding-inline-end / margin-inline-end |
right (LTR) |
"blockStart" |
padding-block-start / margin-block-start |
top |
"blockEnd" |
padding-block-end / margin-block-end |
bottom |
// ✅ correct
"padding": {
"inline": { "$value": "{spacing.sm}", "$type": "dimension" },
"block": { "$value": "{spacing.xs}", "$type": "dimension" }
}
// ❌ wrong
"padding": {
"x": { "$value": "{spacing.sm}", "$type": "dimension" },
"y": { "$value": "{spacing.xs}", "$type": "dimension" }
}Exception — CSS top/bottom/left/right as positioning values (not margin/padding sub-keys) keep their physical names, since they map to CSS position properties, not logical shorthands.
// ✅ positioning — physical names are correct here
"sticky": {
"top": { "$value": "4rem", "$type": "dimension" }
}Interactive states (default, hover, active, disabled…) are expressed as nested keys under the property they modify. The default key is automatically stripped by the build transform.
"color": {
"background": {
"default": { "$value": "{color.brand.default}", "$type": "color" },
"hover": { "$value": "{color.brand.hover}", "$type": "color" }
}
}/* output */
--btn-color-background: var(--color-brand);
--btn-color-background-hover: var(--color-brand-hover);States and camelCase properties compose naturally:
"color": {
"textDecoration": {
"default": { "$value": "transparent", "$type": "color" },
"hover": { "$value": "{color.link.default}", "$type": "color" }
}
}--btn-color-text-decoration: transparent;
--btn-color-text-decoration-hover: var(--color-link);Tokens can reference other tokens using {dotted.path} syntax:
{
"color": {
"link": {
"default": {
"$value": "{color.brand.default}",
"$type": "color"
}
}
}
}In CSS, this maps to var():
--color-link: var(--color-brand);This is the key mechanism behind the primitive → semantic → component hierarchy.
→ tr.designtokens.org/format/#alias
- DTCG specification — W3C Community Group draft
- DTCG GitHub — issues, discussion
- Style Dictionary v5 — token build pipeline, see STYLE-DICTIONARY.md