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}
| Tier | Example | Role |
|---|---|---|
| Primitive | color.blue.500 | Raw values — the palette. |
| Semantic | color.action.primary | Meaning — what a value is for. |
| Component | button.primary.bg.default | Where 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 type | Binds 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
@sorb/corereference —TIERS,ALL_ROLE_IDS, and the resolved-token typedefs.@sorb/seedreference — every Style Dictionary format, includingsorb/resolved-map.- The bridge — where resolution happens.
Works with Figma. Not affiliated with, or endorsed by, Figma. Figma is a trademark of Figma, Inc.