Token JSON format
How to write valid token JSON in SXL Studio: DTCG structure, core fields, the full type set, aliases, math, color modifiers, and validation — every section opens with a table.
Overview
This page describes the JSON format for token files in the Tokens tab. It follows the DTCG shape ($value, $type, $extensions, …). For component files ($type: "composition"), see Composition.
Every node is either a token or a group:
| Node type | Rule | Can hold |
|---|---|---|
| Token node | Has $value | $value, $type, $description, $extensions, $id |
| Group node | No $value (a container) | Child nodes + inherited $type / $extensions |
Key idea Any key starting with $ is a DTCG metadata field. Any other key is a group or token name. Groups pass $type and $extensions down to their children.
File root
The root must be a JSON object (arrays, strings, and numbers are rejected by validation).
{
"colors": {
"brand": {
"primary": {
"$value": "#635BFF",
"$type": "color"
}
}
}
}
Core fields
| Field | Required | Description |
|---|---|---|
$value | Yes (for token node) | The token's value (see forms below) |
$type | No | Token type — explicit or inherited from a parent group |
$description | No | Human-readable description |
$extensions | No | Figma metadata (figma.scopes, codeSyntax, hide, modify) |
$id | No | Stable ID for external tooling |
$value forms
| Form | Example |
|---|---|
| String | "#635BFF", "16px", "Inter" |
| Number / Boolean | 8, true |
| Pure alias | "{colors.brand.primary}" |
| Math expression | "{spacing.base} * 2" |
| Object (composite) | typography, border, grid, … |
| Array (composite) | effects, shadow layers, fill layers, … |
String:
{ "$value": "#635BFF", "$type": "color" }
{ "$value": "16px", "$type": "spacing" }
{ "$value": "Inter", "$type": "fontFamily" }
Number / Boolean:
{ "$value": 8, "$type": "number" }
{ "$value": true, "$type": "boolean" }
Pure alias — one dot-notation path inside {...}:
{ "$value": "{colors.brand.primary}", "$type": "color" }
Math expression (alias embedded in a string):
{ "$value": "{spacing.base} * 2", "$type": "spacing" }
{ "$value": "clamp(16px, {spacing.base} * 4, 64px)", "$type": "sizing" }
Object / Array (composite values):
{
"$value": { "fontFamily": "Inter", "fontSize": "16px", "fontWeight": 500, "lineHeight": "24px" },
"$type": "typography"
}
{
"$value": [{ "type": "DROP_SHADOW", "x": 0, "y": 2, "blur": 8, "spread": 0, "color": "#00000033" }],
"$type": "shadow"
}
Token types ($type)
SXL Studio supports 38 canonical token types. What each type does on Export Variables & Styles is the clearest way to group them.
Exported as Figma variables (17) — scalar tokens that become variables in a collection.
| Figma variable kind | Types |
|---|---|
COLOR | color |
FLOAT (number) | opacity, dimension, number, spacing, sizing, borderWidth, borderRadius, fontSize, lineHeight, letterSpacing, paragraphIndent, paragraphSpacing |
STRING | fontFamily, fontWeight, text |
BOOLEAN | boolean |
Exported as Figma styles (10) — composite tokens that become local styles.
| Style kind | Types |
|---|---|
| Paint | gradient, img, fill |
| Effect | shadow, backdrop-blur, blur, glass, effects |
| Text | typography |
| Grid | grid |
Internal / editable only (11) — fully editable in SXL Studio and used by plugin logic or rendering, but not exported directly as a variable or style: border, strokeStyle, fontStyle, textCase, textDecoration, transition, duration, cubicBezier, template, composition, custom.
Full per-type behavior: Token types.
Note custom (or a clean project-specific $type such as "baseUnit") stays editable in SXL Studio. On export, SXL infers a safe target from the $value shape (#112233 → color, numbers → number, booleans → boolean, CSS gradients → paint). Values it cannot infer safely stay opaque/internal.
$type normalization
Legacy and plural $type values are normalized automatically to the canonical key.
| Input | Canonical |
|---|---|
string | text |
size | sizing |
space | spacing |
fontFamilies | fontFamily |
fontWeights | fontWeight |
fontStyles | fontStyle |
fontSizes | fontSize |
lineHeights | lineHeight |
letterSpacings | letterSpacing |
paragraphSpacings | paragraphSpacing |
paragraphIndents | paragraphIndent |
borderRadii | borderRadius |
textCases | textCase |
textDecorations | textDecoration |
backdropBlur / backgroundBlur / background-blur | backdrop-blur |
layerBlur | blur |
boxShadow | shadow |
Tokens Studio exports (legacy value / type / extensions) can be converted through Migrate from Tokens Studio.
Type resolution and inference
$type is resolved in this order:
| Priority | Source |
|---|---|
| 1 | Token-level $type |
| 2 | Nearest parent group $type |
| 3 | Root-level $type |
| 4 | Auto-inference from $value (fallback) |
If nothing resolves, validation reports an error. When no $type is present or inherited, the parser infers from the $value shape:
$value shape | Inferred type |
|---|---|
true / false or "on", "off", "yes", "no", "1", "0" | boolean |
Number literal (12, 0.5) | number |
Numeric string with unit (16px, 1.5rem, 50%, 200ms) | number |
Color string (#…, rgb(…), hsl(…), color(…)) | color |
CSS gradient (linear-gradient(…), radial-…, conic-…) | gradient |
Stringified 4-number array ("[0.4, 0, 0.2, 1]") | cubicBezier |
Object with r / g / b | color |
Object with typography fields (fontFamily, fontSize, …) | typography |
Object/array with shadow fields (offsetX/Y, blur+color) | shadow |
Object/array with grid fields (pattern, sectionSize, …) | grid |
| Object/array with fill/paint fields | fill |
Object with blur only | blur |
Pure alias ("{a.b}") | resolved from the alias target |
Tip Inference is a fallback for convenience. For reliable exports, set $type explicitly (at token, group, or root level).
$extensions
| Key | What it does |
|---|---|
figma.scopes | Variable scope hints for Figma variable export |
figma.codeSyntax | Dev Mode code snippets (Web, Android, iOS) |
figma.hide | Hide the variable from publishing |
figma.modify | Color modifiers (lighten, darken, alpha, mix) |
figma.scopes — variable scope hints for export:
{ "$extensions": { "figma.scopes": ["ALL_FILLS", "STROKE_COLOR"] } }
The full scope list and per-type defaults live on Scopes & Code Syntax.
figma.codeSyntax — Dev Mode snippets. Use the keys exactly as shown: Web, Android, iOS.
{
"$extensions": {
"figma.codeSyntax": {
"Web": "var(--color-brand-primary)",
"Android": "@color/brand_primary",
"iOS": "Color.brandPrimary"
}
}
}
figma.hide — hide the variable from publishing:
{ "$extensions": { "figma.hide": true } }
figma.modify — color modifiers:
| Field | Values |
|---|---|
type | lighten, darken, alpha, mix |
value | Amount (0–1) |
space | srgb, hsl, lch, oklch, p3 (default oklch) |
color | Target color — required for mix |
{ "$extensions": { "figma.modify": { "type": "lighten", "value": 0.2, "space": "oklch" } } }
figma.modify can be a single object or an array chain applied in order:
{
"$extensions": {
"figma.modify": [
{ "type": "lighten", "value": 0.12, "space": "oklch" },
{ "type": "alpha", "value": 0.6 }
]
}
}
If space is omitted, SXL Studio defaults to oklch. space also accepts the alias $space.
Inheritance. Group $extensions are inherited by children and merged shallowly — a child key overrides the same parent key, and non-overlapping keys combine.
{
"brand": {
"$type": "color",
"$extensions": { "figma.scopes": ["ALL_FILLS"] },
"primary": { "$value": "#635BFF" },
"primary-soft": {
"$value": "{brand.primary}",
"$extensions": { "figma.modify": { "type": "alpha", "value": 0.7 } }
}
}
}
Aliases
| Form | Syntax | Use |
|---|---|---|
| Pure | "{colors.brand.primary}" | The whole value is one referenced token |
| Embedded | "{spacing.base} * 3" | Reference inside a math / composite string |
Rules: one path inside braces, dot notation for segments, no circular references. A pure alias ("{a.b}") is treated as an alias — not as math — and its type resolves from the target token.
Math expressions
A $value string containing an operator or function is evaluated after aliases resolve.
Math applies to numeric token types only: dimension, number, spacing, sizing, borderWidth, borderRadius, opacity, fontSize, lineHeight, letterSpacing, paragraphSpacing, paragraphIndent, duration, blur, backdrop-blur — and to numeric fields inside composites (shadow offsets/blur/spread, typography sizes, transition timings). String-kind values are never evaluated: a text token "37-37" stays the literal "37-37", not 0.
| Category | Supported |
|---|---|
| Operators | +, -, *, /, %, parentheses |
| Constants | pi, e |
| Rounding | round, floor, ceil, trunc |
| Clamping | min, max, clamp |
| Arithmetic | abs, sign, mod, pow, sqrt, hypot |
| Exp / log | exp, log, log2, log10 |
| Trigonometry | sin, cos, tan, asin, acos, atan, atan2 |
{ "$value": "{spacing.base} * 4", "$type": "spacing" }
{ "$value": "round({spacing.base} * 1.5, 2)", "$type": "spacing" }
Notes: round(x, n) rounds to n decimals; rem / em and seconds are normalized during evaluation; an unresolved alias or unknown function invalidates the expression.
Validation
The JSON editor validates:
- JSON syntax;
- DTCG parse errors (a missing resolvable
$type; unknown$typevalues are kept as editable opaque custom tokens); - malformed alias braces;
- unknown token references.
For composition / template files, string references are also checked against workspace token paths, including local embedded composition token namespaces.
Full example
{
"color": {
"$type": "color",
"brand": {
"primary": {
"$value": "#635BFF",
"$description": "Primary brand color",
"$extensions": {
"figma.codeSyntax": {
"Web": "var(--color-brand-primary)",
"Android": "@color/brand_primary",
"iOS": "Color.brandPrimary"
}
}
},
"primary-soft": {
"$value": "{color.brand.primary}",
"$extensions": {
"figma.modify": [
{ "type": "lighten", "value": 0.1, "space": "oklch" },
{ "type": "alpha", "value": 0.65 }
]
}
}
}
},
"spacing": {
"$type": "spacing",
"base": { "$value": "4px" },
"md": { "$value": "{spacing.base} * 4" }
}
}