Resolution
Token resolution
Themvora tokens are more than static key-value pairs. A reference like $colors.primary is resolved at build time, expressions like 2 * 16px are evaluated, and derived tokens like auto() produce contrast-safe foreground colors automatically.
1Token references
Use $ prefix or {braces} syntax to reference another token by its flattened path. References are resolved after the base theme and extends are merged, so you can override a single source and every reference follows.
import { defineTheme } from "@themvora/core";
const theme = defineTheme({
name: "brand",
tokens: {
colors: {
primary: "#3b82f6",
// Reference another token with $ prefix
primaryHover: "$colors.primary",
// Or use the brace syntax
primaryMuted: "{colors.primary}",
},
spacing: {
sm: "8px",
md: "16px",
lg: "$spacing.sm + $spacing.md", // 24px
},
},
});2Expressions
Token values containing only numbers, operators, and units are recognized as expressions. The expression evaluator supports +, -, *, /, and parentheses. Units are preserved through evaluation.
import { evaluateExpression, isExpression } from "@themvora/core";
// Numeric expressions with +, -, *, / and parentheses
isExpression("16 + 8"); // true
isExpression("2 * (12 + 4)"); // true
isExpression("#3b82f6"); // false
// Evaluate resolves the expression, preserving units
evaluateExpression("8 + 16"); // "24"
evaluateExpression("4 * 4px"); // "16px"
evaluateExpression("(100 - 20)%"); // "80%"
evaluateExpression("2 * (12 + 4)px"); // "32px"
// Used inside token definitions
const theme = defineTheme({
name: "computed",
tokens: {
spacing: {
base: "4px",
double: "2 * $spacing.base", // 8px
triple: "3 * $spacing.base", // 12px
},
},
});3Derived colors
The auto() function infers which background token to use based on the token's own name — a token named primaryForeground looks up primary and returns black or white for WCAG-safe contrast. You can also call contrast() explicitly with a hex value.
import { defineTheme, contrast, auto } from "@themvora/core";
const theme = defineTheme({
name: "auto-contrast",
tokens: {
colors: {
primary: "#3b82f6",
// auto() infers the path from the token name
// "primaryForeground" → looks up "primary" → returns black or white
primaryForeground: "auto()",
card: "#f8fafc",
cardForeground: "auto()",
destructive: "#ef4444",
destructiveForeground: "auto()",
},
},
});
// Or use contrast() with an explicit color
const manual = defineTheme({
name: "manual-contrast",
tokens: {
colors: {
primary: "#3b82f6",
primaryForeground: "contrast(#3b82f6)", // → "#000000"
},
},
});
// Direct utility usage
contrast("#3b82f6"); // "#000000" (luminance > 0.179)
contrast("#000000"); // "#ffffff" (luminance <= 0.179)auto() recognizes the *Foreground and *Fg suffixes. Any token with one of these suffixes will automatically resolve against its base color.4Resolution order
When resolveTokens() is called, it processes the token tree in this order:
- 1Base tokens— Literal values from the theme definition are collected into a flat lookup map.
- 2Extends merge— The parent theme's tokens are merged underneath — child values override parent values.
- 3Overrides— Family-scoped or runtime overrides are applied last in the merge.
- 4References— $ref and {ref} tokens are resolved by walking the flat map, with cycle detection.
- 5Expressions— Numeric expressions (16 + 8, 2 * 4px) are evaluated and replaced with computed values.
- 6Derived tokens— auto() and contrast() calls compute final values using already-resolved backgrounds.
import { resolveTokens } from "@themvora/core";
// Given a theme that uses all three mechanisms:
const theme = {
colors: {
// 1. Literal value
primary: "#3b82f6",
// 2. Reference — resolved after base/extends
hover: "$colors.primary",
// 3. Expression — evaluated after references resolve
lightened: "#3b82f6 + #111111",
// 4. Derived — computed last
primaryForeground: "auto()",
},
};
const resolved = resolveTokens(theme);
// resolved.colors.primary → "#3b82f6"
// resolved.colors.hover → "#3b82f6"
// resolved.colors.lightened → "#4c9307" (numeric hex add)
// resolved.colors.primaryForeground → "#000000"5API Reference
resolveTokens(tokens)
Takes a ThemeTokens object and returns a new object with all references, expressions, and derived tokens fully resolved.
import { resolveTokens } from "@themvora/core";
const tokens = {
colors: {
primary: "#3b82f6",
hover: "$colors.primary",
foreground: "auto()",
},
spacing: {
sm: "8px",
md: "16px",
lg: "$spacing.sm + $spacing.md",
},
};
const resolved = resolveTokens(tokens);
// All references, expressions, and derived values resolved
// resolved.colors.hover → "#3b82f6"
// resolved.colors.foreground → "#000000"
// resolved.spacing.lg → "24"flattenTokens(tokens)
Flattens a nested ThemeTokens object into a dot-separated flat map. Useful for building lookup tables or custom resolution logic.
import { flattenTokens } from "@themvora/core";
const tokens = {
colors: {
primary: { default: "#3b82f6", hover: "#2563eb" },
surface: "#f8fafc",
},
spacing: { sm: "8px" },
};
const flat = flattenTokens(tokens);
// {
// "colors.primary.default": "#3b82f6",
// "colors.primary.hover": "#2563eb",
// "colors.surface": "#f8fafc",
// "spacing.sm": "8px",
// }hasTokenReferences(value)
Returns true if the string contains a $ or {} token reference.
import { hasTokenReferences } from "@themvora/core";
hasTokenReferences("$colors.primary"); // true
hasTokenReferences("{spacing.sm}"); // true
hasTokenReferences("8px + 4px"); // false
hasTokenReferences("#3b82f6"); // falseevaluateExpression(expr)
Evaluates a numeric expression string and returns the result. If the input is not a valid expression, it is returned unchanged.
import { evaluateExpression } from "@themvora/core";
evaluateExpression("8 + 16"); // "24"
evaluateExpression("2 * (12 + 4)px"); // "32px"
evaluateExpression("(100 - 20)%"); // "80%"
evaluateExpression("#3b82f6"); // "#3b82f6" (not an expression)