Tokens & taxonomy

Sorb speaks the open DTCG token format and resolves it into the exact values your app renders — then binds each value to the right CSS property by type, so there are no hand-authored mappings to maintain.

DTCG in, CSS variables out

Sorb reads your tokens in the DTCG format — the open standard that Style Dictionary and the DTCG community toolchain already speak. Your token file works outside Sorb too; Sorb doesn't lock it in.

At runtime, resolved tokens reach your app as CSS custom properties:

color: var(--button-primary-bg-default, #f26722);

Change the variable's value and the component re-skins — no component edit, no rebuild.

Tiers, one file each

Sorb organizes tokens into three tiers, one DTCG file per tier, each referencing the tier below it — the common design-token taxonomy:

tokens/
  primitive.json    raw values (the palette/scales) — no references
  semantic.json     role aliases — reference primitives with {ref}
  component.json    per-component tokens — reference semantics with {ref}
TierExampleRole
Primitivecolor.blue.500Raw values — the palette.
Semanticcolor.action.primaryMeaning — what a value is for.
Componentbutton.primary.bg.defaultWhere a value is used.

When the plugin syncs Variables from code, it creates or updates three matching Figma Variable collections (Primitives, Semantic, Component).

{ref} aliases and $version

Every non-primitive value is a DTCG reference, not a copy — semantic.json points at primitive.json by id, in curly braces:

{
  "$version": "1.0.0",
  "color": {
    "action": {
      "primary": { "$value": "{color.blue.500}", "$type": "color" }
    }
  }
}

Sorb follows the chain and resolves it to the literal value (#0F65EF) at build time — nothing in your running app ever sees an unresolved {ref}. $version lives at the root of each tier's file, independently — bumping component.json's version doesn't touch primitive.json's. The build lifts each file's $version out before merging the three trees (so three root keys never collide) and re-emits them as one { primitive, semantic, component } object your tooling can read back.

Resolution

sorb dev reads your DTCG sources and resolves aliases, modes, and references into a flat map of concrete values, written to .sorb/resolved.json in the sorb/resolved-map shape — one entry per token:

{
  "id": "color.action.primary",
  "cssVar": "--color-action-primary",
  "value": "#0F65EF",
  "tier": "semantic",
  "type": "color"
}

A token marked $deprecated in its source carries two extra fields: deprecated: true, and replacedBy when the source names a successor id ($extensions.sorb.replacedBy) — sorb check and the plugin both surface these rather than silently binding to a token you've moved off of.

.sorb/resolved.json is produced by the live bridge, not hand-maintained — it's the values your app actually renders.

Canonical role ids

Semantic tokens don't have to be named the same across every kit — a Bootstrap-flavored app and a Tailwind one can each keep their own semantic names. What has to line up is the small set of canonical role ids Sorb's framework-target formats resolve against: color.brand, color.surface, radius.control, and so on — the full list is ALL_ROLE_IDS in @sorb/core. A format calls resolveRole('color.brand', roleMap); with no roleMap supplied, role ids resolve to themselves, which is already correct for a kit (like the reference Jane's Jeans kit) that uses the canonical ids as its own semantic token ids. A kit with different names supplies overrides:

// sd.config.js — only needed when your semantic ids differ from the canonical ones
{
  options: {
    roleMap: { 'color.brand': 'jj.brand.500' },
  },
}

Binding by type

Sorb matches each token to the CSS property it belongs on, by type and affinity:

Token typeBinds to
color (fill)background
color (stroke)border
color (text)text color
dimension (radius)corner radius

This is automatic — you don't write or maintain figma.connect()-style prop mappings. Fills go to backgrounds, strokes to borders, text colors to text, radii to corners.

Value validation

Values are validated by type before they're applied: hex / rgb / hsl for colors; px / rem / em / % / vh / vw / pt for dimensions; true / false for booleans. An invalid value is rejected (never written), so a typo can't reach your running app.

Next

Works with Figma. Not affiliated with, or endorsed by, Figma. Figma is a trademark of Figma, Inc.