Variables and themes
On this page4 sections
1.0.0, frozen 2026-10). Backward compatible within 1.x (§16.4). Supersedes the draft v0.1, kept as a historical record; 0.1 files open through the 0.1 → 1.0 migration (§16.2).https://getkimo.design/schema/kimo-1.0.json (JSON Schema draft 2020-12), generated into packages/core-schema/schema/kimo-1.0.schema.json . The 0.1 schema stays published at …/kimo-0.1.json (schema/kimo-0.1.schema.json, frozen).@kimo/core-schema (packages/core-schema). Where this document and the implementation disagree, that is a bug in one of them; file an issue.docs/teardown.md §10. Every place where this spec resolves an ambiguity in, or deviates from, that section is listed in §20.10.1 Variables
"variables": {"surface": { "type": "color", "value": [ { "value": "#FFFFFF", "when": { "mode": "light" } },{ "value": { "$ref": "ink-900" }, "when": { "mode": "dark" } } ],"group": "color.surface", "description": "Page background" }}
| Field | Meaning |
|---|---|
type | color, number, string, boolean; composite (feature tokens/composite): typography, shadow, dimension. |
value | A plain value used under every theme, or a themed value: a non-empty array of entries { value, when?: record axis key → value }. An array is themed exactly when every element is an object with a value member (shadow arrays and plain values never qualify). |
description | Free text. |
group | Dotted group path for DTCG export (e.g. color.surface). |
typecolor, number, string, boolean; composite (feature tokens/composite): typography, shadow, dimension.value{ value, when?: record axis key → value }. An array is themed exactly when every element is an object with a value member (shadow arrays and plain values never qualify).descriptiongroupcolor.surface).Plain values by type: color → Color; number → Num; string → string | Ref; boolean → boolean | Ref; typography → a TextStyle without typography, or Ref; shadow → a shadow Effect or an array of them, or Ref; dimension → { value: number, unit: "px" } (px only in 0.x and 1.x), or Ref. A value that is a binding is an alias; an alias MUST name a variable of the same type.
10.2 Bindings and types
A binding MUST name an existing variable (VARIABLE_MISSING); alias:name names a variable of an imported library, which is never copied into the consumer. The bound variable's type MUST fit the property:
| Property | Accepted variable types |
|---|---|
fill, color, colors, stroke paint, gradient stop color | color |
opacity, gap, crossGap, pad, radius, stroke width / t r b l, shadow x y blur spread, effect radius, w, h, text size weight lineHeight letterSpacing, icon weight | number, dimension |
visible, clip | boolean |
content, icon, font | string |
effects | shadow |
typography | typography |
args of a text / boolean prop | string / boolean |
script inputs, shader uniforms, enum options, enum target value | any |
fill, color, colors, stroke paint, gradient stop colorcoloropacity, gap, crossGap, pad, radius, stroke width / t r b l, shadow x y blur spread, effect radius, w, h, text size weight lineHeight letterSpacing, icon weightnumber, dimensionvisible, clipbooleancontent, icon, fontstringeffectsshadowtypographytypographyargs of a text / boolean propstring / booleaninputs, shader uniforms, enum options, enum target value10.3 Themes
themes declares axes, each with its values; the first value is the default. A node's theme pins axes for its subtree; keys are axis keys (alias:axis for a library's axis) and values MUST be declared values of that axis (THEME_AXIS_UNKNOWN, THEME_VALUE_UNKNOWN). The same applies to when keys and values.
10.4 Resolution (normative)
- Effective theme of a node. Start from the defaults: the first value of every local axis, and for every loaded imported library
alias, the first value of each of its axes under the keyalias:axis. Walk from the root to the node along its placement path (parentlinks, which include instance placement andatnodes), so instances inherit from where they sit. At each node withtheme, overwrite only the named axes. For nodes inside an expanded instance the placement path is the expanded one (§9.8 rules 2 and 4). - Library axes are namespaced
alias:axisand default from the library. - Variable value. A plain value applies under every theme. For a themed value, an entry matches when every axis named in its
whenequals the effective value of that axis; axes it does not name are ignored (partialwhenis allowed). Entries withoutwhen, or withwhen: {}, are fallbacks only and never candidates. Among matching entries the last one in list order wins (no specificity ranking). - No candidate. Use the fallback entry — the last entry without
when(or withwhen: {}) — if there is one, otherwise the first entry. In both cases emit the lintTHEME_NO_MATCH(variable, effectiveTheme). - Aliases resolve recursively with cycle detection: a cycle is the error
VARIABLE_CYCLE. - Library variables (
{ "$ref": "alias:name" }) resolve inside the library: awhenkeyaxisof the library reads the consumer's effective value ofalias:axis, or the library's default for that axis. Paste-without-import copies the variables, with a "use existing" / "add renamed" choice.