-
Notifications
You must be signed in to change notification settings - Fork 1
design tokens(draft)
- Overview
- Figma Variable Structure and Collections
- Exporting Tokens to DTCG JSON
- Transforming Tokens to Sass Maps with Terrazzo
-
Future Specification Improvements
- 1. Figma Mode to DTCG Mapping Rules
- 2. Phase 1 Scope Boundary (Variables vs Styles)
- 3. Plugin Error Handling and Validation Strategy
- 4. Terrazzo Configuration Specification
- 5. Legacy Compatibility Implementation Details
- 6. CI/CD Integration and Automation
- 7. Testing Strategy
- 8. Developer Workflows and Troubleshooting
- 9. Mode Handling in CSS Generation
- 10. Reference Resolution Mechanism
- 11. Token Enrichment Process
- 12. Complex Dimension Value Structure
- 13. Token Naming Conventions and Semantic Standards
Product Design Team
Developer Name:
Designer Name:
- Peer Developer:
- Design Manager: Svilen Dimchevski
- Product Owner: Radoslav Mirchev | Date:
| Version | Users | Date | Notes |
|---|---|---|---|
| 1 | Initial draft | Date 07-11-2025 |
This specification defines a workflow to translate Figma variable collections into W3C Design Tokens (DTCG) JSON files, and then convert those tokens into Sass maps consumable by Ignite UI’s theming framework. The goal is to maintain a single source of truth in Figma for design values (colors, typography, spacing, etc.) and ensure those values carry through to code with full fidelity (including theming modes and references). The process involves a custom Figma plugin to export variables in DTCG format, followed by a Terrazzo-based pipeline to transform the JSON tokens into Sass. This end-to-end flow is illustrated below:

Figure 1: Process from Figma to Sass – Figma variables are exported as DTCG tokens via a custom plugin, then processed by Terrazzo with a Sass transformer to generate Sass maps for the design system.
In Figma, design tokens are organized using Variable Collections. Each collection acts as a bucket for related variables and their modes. We will use separate collections for Colors, Typography, Spacing, Shadows, and Components, aligning with the design system’s domains. This separation ensures that, for example, color themes (light/dark) are isolated from other types of variables like spacing scales.
Within a collection, variables are hierarchically grouped by naming paths using the "slash" (/) in Figma. For example, a variable named Button/Background/Default will appear under a Button group, then a Background subgroup, with the variable Default inside it. Figma's UI displays these groups in the Variables panel (as folders), making it easy to organize tokens. In the Components collection, we will leverage this to group variables by component name (Button, Card, Avatar, etc.), and within each, by the design property (Background, Foreground, Border, Shadow, etc.). For instance, all Button-related tokens can live under the Button group with subgroups for its parts. This convention improves clarity for designers and developers – Figma even shows the full path in Dev Mode (joining groups with hyphens, e.g. Button-Background-Default for the token above).

Figure: Example Figma “Color – Semantic” collection (for component-specific colors). Shown is the Button group with subgroups Background and Label, each containing tokens like Default, Hover, Pressed. The table columns for Light and Dark indicate the two mode values for each token. In this setup, the Button background tokens are aliases referencing base color tokens (e.g. “Blue/300”) for the Light theme and alternate tokens (e.g. “Blue/100”) for Dark theme.
We distinguish primitive tokens (raw values with no contextual meaning) from semantic tokens (aliases that carry contextual names) . Primitive tokens reside in collections like Colors or Spacing – for example, a color variable Blue/500 with value #2D6AE3 or a spacing variable Spacing/16 with value 16px. These represent core values (options) without specific usage tied to them. Semantic tokens, on the other hand, live in the Components (or other semantic) collection and reference those primitives to convey usage intent. For instance, a token Toast/Background/Default in a semantic collection might alias the primitive Neutral/400 color . This tells designers and developers that the Toast background uses that neutral color, rather than an arbitrary value. By using aliases (references) in Figma, any change to a primitive value will propagate to all semantic tokens that reference it, reinforcing single source of truth .
Figma currently supports four variable types: Color, Number (float), Boolean, and String . Our Figma tokens will use these types appropriately for each domain (colors as Color type, spacing/radius as Number, toggles as Boolean, etc.). Figma does not have native composite types for things like shadows or typography styles, so complex design tokens will be represented via multiple variables or as styles. For example, a Shadow token in design terms (which includes color, blur, offsets) might be broken into multiple Figma variables (color and numeric values) or managed as a Figma Effect Style. These will later be combined in the token JSON if needed. Typography styles (font, size, line-height, etc.) could be managed via separate variables or Figma Text Style definitions – our plugin can optionally include styles in the export for completeness. In summary, we will map Figma’s 4 types to the corresponding DTCG token types: Color → $type: "color", Number (float) → $type: "dimension" (with unit), Boolean → $type: "boolean", String → $type: "string" . (Figma’s “float” numbers will be assumed to represent pixel dimensions; our export will attach a unit "px" to these to form a proper dimensional token .)
Figma’s mode feature will be used to capture theming variations (e.g. Light vs Dark mode values). Each collection can define one or more modes. For colors, we expect at least Light and Dark modes in the Colors collection, allowing each color variable to hold two values . Other collections can use modes as needed (for example, a Size collection might have Small, Medium, and Large modes, or a Typography collection might have scaling modes). In our setup, most primitives (spacing, etc.) will likely use only a default mode (no variation), whereas the Colors collection and possibly the Components (semantic) collection will support light/dark modes. Designers should define modes in Figma for any collection where tokens need theme-specific values, and assign the appropriate values for each mode in the Figma UI. The variables shown in the figure above demonstrate how the Button tokens have different alias targets for Light vs Dark – for example, button/background/idle references primary/300 in Light and primary/100 in Dark. This mode data will be preserved in the exported design token files.
It is critical that token relationships defined in Figma (one variable referencing another) are preserved in the design token output. The plugin will not “hard-code” resolved values for aliases; instead it will output a reference in the DTCG format. For example, if a Figma variable “button/foreground/idle” is an alias of “gray/800” (a color), the JSON token will use a reference like "{colors.gray.800}" as its value rather than duplicating the hex code. This way, the dependency remains clear – Button Foreground Idle will always pull from the "gray/800" token. Designers should use Figma’s aliasing feature to link variables (rather than copying values) whenever one token should derive from another. Our specification enforces that these links be reflected in code.
Additionally, designers are encouraged to fill out the description field for each variable in Figma. These descriptions (e.g. “The background color for contained buttons in idle state”) will be carried into the token JSON and ultimately serve as documentation for developers and in style guides. They help clarify intent and are especially useful for semantic tokens where the usage might not be obvious just from the name. Descriptions can be viewed in Figma’s Inspect or Dev Mode, and we will include them in the output as $description properties for each token .
To extract the Figma variables into code, we will develop a custom Figma plugin that utilizes Figma's Plugin API to fetch all local variables and their metadata. This plugin's behavior will be modeled on existing solutions for tokenization, but refined to fully conform to the latest DTCG specification. Key aspects of the export format and process are outlined below:
-
One JSON File per Collection: Each Figma variable collection will be exported as a separate JSON file containing the tokens of that collection. For example,
colors.json,typography.json,spacing.json,elevations.json, andcomponents.json. This separation mirrors how the design team organizes tokens and makes it easy to integrate or update specific categories without affecting others. (If needed, we can also produce a single consolidated file, but the primary approach is to keep collections modular). -
DTCG-Compliant Structure: The JSON files will adhere to the W3C Design Tokens format (latest spec, at the time of writing 2025.10) so they can be used with modern token tools. In practice, this means:
- Using DTCG key names:
$value,$type,$description, etc., rather than custom or legacy naming. - Nesting tokens according to their group hierarchy. For instance, a Figma variable named "button/background/idle" in the Components collection would appear in JSON as:
- Using DTCG key names:
{
"button": {
"background": {
"idle": {
"$type": "color",
"$value": "{colors.primary.300}"
}
}
}
}where {colors.primary.300} is a reference to a token in the colors collection. The JSON keys follow Figma group names exactly (with appropriate normalization for any spaces or special characters). We will transform naming to a consistent case or delimiter for code, but since Terrazzo can handle either slashes or dot notation transparently, we may keep names as-is or convert / to . in keys depending on what Terrazzo expects. The DTCG spec suggests using . as hierarchy separators in token IDs, but it is not strictly required.
For each token, the plugin will include the following properties:
-
Type: The
$typefield will denote the token’s type (color, dimension, etc.), mapped from Figma’s variable type. -
Description: As noted, if a Figma variable has a description, it will be added as a
$descriptionfield in the token JSON .
We will use DTCG’s standard types:
-
Figma Color →
$type: "color"(value will be a color object or string in a chosen format, e.g. hex). -
Figma Number (for numeric values like spacing, radii) →
$type: "dimension"with a unit. By default we’ll interpret these as pixels, so a Figma float 8 becomes:
{
"$type": "dimension",
"$value": {
"unit": "px",
"value": 8
}
}-
Figma Boolean →
$type: "boolean"(the$valuekey will be set to will betrue/false). -
Figma String →
$type: "string"(the$valueis the string content).
Note
Figma does not support complex types like gradient, shadow, typography directly as variables. If such tokens are needed, we’ll either export them via styles or assemble them from primitives. For example, a Shadow token could be represented with $type: "shadow" and a composite $value object if we collect all necessary pieces (color, offsets, blur) from variables or styles . Our initial scope maps the four basic types; extending to composite types can be an evolution of the plugin.
For tokens with multiple mode values (e.g. a color that has different light and dark values), we will utilize the $extensions.modes property as recommended. In the exported JSON, the token’s $value will hold the default mode’s value, and under $extensions: { "modes": { } } we will list the alternative mode values keyed by mode name or identifier.
For example:
{
"button": {
"idle": {
"$type": "color",
"$value": "{colors.secondary.500}",
"$extensions": {
"modes": {
"dark": {
"$value": "{colors.secondary.400}"
}
}
}
}
}
}This indicates the token button/idle is secondary/500 in light mode and switches to secondary/400 in dark mode. We use mode names like “dark” as keys for clarity (assuming mode IDs can be mapped to names). Terrazzo and other tools will read this and know to apply the alternate value for the dark theme. (Our plugin bases this on Figma’s defaultModeId and the values per mode that Figma provides in its API.)
Rules:
- The collection's
defaultModeIddetermines the token's root$value. - All other modes are added to
$extensions.modeskeyed by mode name. - Mode names from Figma are transformed to lower case (e.g. "Light" -> "light", "Dark" -> "dark").
- If a variable has the same value across all modes,
$extensions.modesis omitted.
If a token is an alias of another, the $value will be a reference string in curly braces per the DTCG syntax. For cross-collection references, we may include the collection name in the path (e.g. {colors.primary.500} or use some agreed prefix. The plugin will ensure the syntax is correct.
Optionally, the export can include Figma-specific IDs or scopes if we need them for traceability. For example, we could include the Figma variable ID, style ID, or scope (like ["ALL_SCOPES"] or ["COLOR"] tags that Figma provides to indicate usage scope. By default, we might exclude these to keep the token files clean. However, for completeness, an option could allow including them under $extensions.figma. This could help in verifying we captured everything or in round-tripping tokens back to Figma if needed. For the initial implementation, we will likely not include Figma’s internal IDs unless a use-case emerges.
Below is a conceptual example combining several of the above points (note: for illustration; not actual file syntax):
{
"button": {
"$description": "Design tokens for button component",
"background": {
"idle": {
"$type": "color",
"$value": "{colors.secondary.500}",
"$description": "Default background color for buttons",
"$extensions": {
"modes": {
"dark": {
"$value": "{colors.secondary.400}"
}
},
"legacy": {
"cssVar": "--button-background"
}
}
},
"hover": {
"$type": "color",
"$value": "{colors.secondary.800}",
"$description": "Button background on hover",
"$extensions": {
"modes": {
"dark": {
"$value": "{colors.secondary.600}"
}
}
}
}
},
"border": {
"radius": {
"$type": "dimension",
"$value": {
"value": 4,
"unit": "px"
},
"$description": "Border radius for buttons"
}
}
}
}In this snippet, button/background/idle and hover are color tokens referencing colors.secondary.* values, with alternate dark mode values specified. button/border/radius is a dimension token (4px). The structure is nested exactly per the group path. Each token has a description, and the idle background has a legacy CSS variable name recorded. This is the kind of JSON our plugin will generate, following the DTCG format. By comparison, an earlier example from industry practice showed semantic token JSON with light/dark keys – our format encapsulates those under the DTCG $extensions.modes to remain spec-compliant.
The plugin will handle converting color values to a chosen format. We’ll likely export colors as HEX or RGBA strings for simplicity unless a different format is required (the plugin can support hex, rgba, hsla, etc. – HEX is a safe default). If a color has opacity in Figma, we might use hex8 (e.g. #RRGGBBAA) or an rgba() string .
Finally, once the plugin runs, designers or developers can download the JSON files. If running the plugin within Figma, we’ll provide a way to save each collection’s JSON (or a combined JSON) to disk. If using the REST API approach, we’d run a script that fetches the data and writes out the JSON. We will ensure this process is repeatable and document the steps so it can be part of the design-to-development pipeline (potentially even automated on version updates).
This section defines how DTCG component tokens exported from Figma are transformed into Sass component schemas and CSS variables.
[!INFO] The initial implementation covers component tokens only (e.g. button, card, avatar). Primitive collections (e.g. colors, typography, elevation) are not consumed directly from DTCG in this phase. Instead, the primitive tokens will be added in CSS via existing Ignite theming mechanisms. Future phases may extend Terrazzo to consume primitive collections directly from DTCG.
The Terrazzo transformer receives:
A file such as components.json with tokens grouped by component name and nested paths, e.g.:
- button.background.idle
- button.background.hover
- button.border.radius
Each token exposes:
- $type (e.g. "color", "dimension")
- $value (literal or DTCG reference string)
- $description (from Figma)
- Optional $extensions (may be enriched later)
A repo-maintained file mapping new DTCG token paths to old schema property keys:
- Keys are dot-separated DTCG paths under the components collection.
- Values are the legacy Ignite schema keys currently used in existing Sass schemas (e.g. the keys passed to var-get / used in existing component maps).
- If absent, no alias is added (the token has no legacy equivalent and can be considered “new only”).
Example:
{
"button.background.idle": "button-background",
"button.background.hover": "button-hover-background",
"button.border.radius": "button-border-radius"
}The enriched token objects (with $extensions.alias where applicable) are then used as the source of truth for Sass schema generation.
This ensures the mapping between new DTCG token paths and old Ignite schema keys is explicit and version-controlled (in the alias JSON), but also available at the token level via $extensions.
For each component (e.g. button, card), the transformer creates a Sass map schema that mirrors the DTCG hierarchy.
Example for button (simplified):
$button: (
background: (
idle: (
$type: 'color',
$value: '{colors.primary.500}',
$description: 'Button background (idle)',
$extensions: (
alias: 'button-background',
modes: (
dark: '{colors.primary.600}'
)
)
),
hover: (
$type: 'color',
$value: '{colors.primary.600}',
$extensions: (
alias: 'button-hover-background'
)
)
),
border: (
radius: (
$type: 'dimension',
$value: (
default: (
value: 4,
unit: 'px'
),
min: (
value: 0,
unit: 'px'
),
max: (
value: 20,
unit: 'px'
)
),
// Grouped value structure for border-radius($default, $min, $max)
$extensions: (
alias: 'button-border-radius'
)
)
)
);Requirements:
- Schema is component-scoped:
- One schema map per component (e.g. $button, $card).
- Leaf nodes must:
- Preserve $type and $value from DTCG.
- Preserve $description (if present).
- Include $extensions.alias when an alias is provided by the mapping file.
- Include any additional structured extensions needed for special semantics.
Note
The schema remains DTCG-shaped and declarative: no var(), no Ignite UI Theming-specific function calls embedded. All behavior is derived later based on $type and $extensions.
A resolver function (conceptually resolve-token-value) operates on schema leaf nodes to compute the Sass expression that should be assigned to the component CSS variable for that token.
-
$node– the leaf map containing$type,$value,$extensions,$description. -
$path– the component-local path, e.g. ('background', 'idle') or ('border', 'radius').
- Read
$type:- "color" – interpret
$valueaccording to the existing theming rules (literal or alias to an existing palette). No DTCG color primitives are consumed at this stage; color resolution is delegated to the existing Ignite theming mechanisms or to literal values defined in DTCG. - "dimension" – interpret either as:
- A simple dimension object:
{ value: 4, unit: 'px' }→ returns the literal value - A composite dimension object with default/min/max structure (for roundness) → see below
- A simple dimension object:
- "color" – interpret
- Read
$extensions:- This grouped value structure keeps all related constraint values together in
$value, avoiding confusion with$extensions.modeswhich is reserved for theming variations (light/dark). - For other categories (spacing, typography, etc.), resolution may simply return the literal or apply any existing helpers; the exact mapping is intentionally kept implementation-specific.
- This grouped value structure keeps all related constraint values together in
- The resolver does not concern itself with legacy schema keys; those are used later when building backwards-compatible structures.
A tokens mixin is responsible for turning a component schema into component-scoped CSS custom properties.
/// Emits CSS custom properties for a component based on its DTCG-shaped schema.
/// @param $component-name e.g. 'button'
/// @param $schema component schema map (e.g. $tokens-button-schema)
/// @param $selector CSS selector for scoping (default theme root)
@mixin tokens($component-name, $schema, $selector: :root);- Flatten $schema into (path → node) pairs.
- For each leaf node:
- Determine the canonical CSS var name based on $component-name and $path:
- Call
resolve-token-value($node, $path)to get the Sass expression.
- Emit into
$selector:
#{$selector} {
--{$component-name}-#{$normalized-path}: #{resolve-token-value($node, $path)};
}The result is a set of component-level CSS variables whose values are:
- Literal colors / dimensions, or
- Computed expressions using existing Ignite helper functions (e.g. border-radius from mode values),
but whose names are consistently derived from the new DTCG component+path convention.
At this stage, primitives are not consumed directly from DTCG. The assumption is that:
- Component token
$valuefields may contain either literal values (e.g. "#2D6AE3") or DTCG reference strings (e.g. "{colors.primary.500}"). - When a reference string is encountered, it is passed through to the existing Ignite theming helper functions, which are responsible for resolving these references against the existing palette/primitive token system already in use.
- In future phases, primitive collections (colors, spacing, etc.) may be consumed directly from DTCG, at which point the resolver would handle reference resolution internally.
The alias extension captured from the alias map is used to maintain compatibility with existing Ignite schema property names and APIs.
- For each schema leaf that has $extensions.alias, the transformer MUST:
- Provide a way to construct a legacy-compatible view of the component schema (or theme) where the old property key is preserved.
- Example: build a secondary map (per component or per theme) keyed by alias, pointing to the same resolved values, so existing code that does var-get($theme, 'button-background') can still resolve correctly.
The exact shape of this compatibility map can be decided during implementation, but the spec requires:
- The mapping DTCG path → legacy schema key is captured in $extensions.
- The Sass side has enough information to:
- Either generate legacy-style schemas, or
- Generate an adapter map that bridges from old property keys to new token-derived values.
This ensures we can move to DTCG-shaped component schemas without breaking existing usage of var-get and legacy schema names.
An optional token helper function provides a simple, token-centric way to consume component CSS variables:
/// Returns a CSS custom property reference for a component token.
/// @param $component-name e.g. 'button'
/// @param $path... e.g. 'background.idle' or ('background', 'idle')
@function token($component-name, $path...);- It must use the same name-building rule as the tokens mixin.
- It returns:
var(--ig-<component-name>-<path-as-dashes>, <fallback>)where the fallback is:- For tokens referencing primitives (colors, shadows, border-radius, etc.): a CSS custom property reference to the corresponding global primitive variable (e.g.
var(--ig-primary-500)) - For tokens with literal values: the resolved literal value from the DTCG token (e.g.
#2d6ae3or4px)
- For tokens referencing primitives (colors, shadows, border-radius, etc.): a CSS custom property reference to the corresponding global primitive variable (e.g.
This function is additive and does not replace var-get. Legacy code can continue to use var-get with legacy schema keys; new code can opt into token with DTCG-style paths.
[!TODO] The following areas need to be addressed in future versions of this specification:
Context: The spec explains that both Figma and DTCG support modes, but doesn't specify the exact mapping algorithm.
Needed:
- Define how Figma's
collection.defaultModeIddetermines which value goes into the token's root$value - Specify that non-default modes are added to
$extensions.modeskeyed by mode name (normalized to lowercase) - Clarify behavior when a variable has identical values across all modes (omit
$extensions.modes?)
Context: Figma has both Variables API and Styles API. The spec mentions shadows/typography but doesn't clearly define what's in/out of scope.
Needed:
- Explicitly state that Phase 1 only exports Figma Variables (Color, Number, Boolean, String)
- Document that Effect Styles (shadows), Text Styles (typography), and Paint Styles (gradients) require the Styles API and are deferred to Phase 2
- Provide a workaround: manually-authored DTCG files for composite types that Terrazzo can consume alongside Figma-exported tokens
- Define what Phase 2 will include and how composite token types will be structured
Add to lines 89-92 area: Clear table of supported vs unsupported types in Phase 1
Context: No specification for how the plugin handles error conditions during export.
Needed (add new section after line 138):
Fatal Errors (block export):
- Broken references: Variable references non-existent variable
- Type mismatches: Number variable references Color variable
- Circular references: A → B → C → A
Warnings (export with notification):
- Missing mode values: Variable has value in Light but not Dark mode
- Empty descriptions: Semantic tokens without descriptions
- Scoped variables: Variables with component-specific scope restrictions
Export Behavior:
- For missing mode values: Use default mode value for all modes (with warning)
- For scoped variables: Include
$extensions.figma.scopesarray for traceability - Log all warnings to console and export a validation summary file
Context: The spec mentions "Terrazzo with a Sass transformer" but doesn't show the configuration.
Needed (add new section after line 196):
- Complete
terrazzo.config.jsexample showing:- Token input paths (which JSON files)
- Output directory structure
- Custom Ignite UI plugin reference
- Plugin configuration (alias map path, resolver mapping, etc.)
- Document custom transformer responsibilities:
- Type-aware resolution (call appropriate Ignite helpers per
$type) - Alias mapping (apply legacy schema keys from JSON map)
- Mode handling (generate Sass structures for theme modes)
- Component grouping (output one Sass file per component)
- Type-aware resolution (call appropriate Ignite helpers per
Context: Lines 361-376 describe the goal but not the implementation approach.
Needed:
- Choose between two implementation strategies:
- Option A (Recommended): Dual schema generation - generate both DTCG-shaped and flat legacy schemas per component
- Option B: Runtime adapter - translate legacy keys to DTCG paths at resolution time
- Document the chosen approach with complete code examples
- Show how
var-get($theme, 'button-background')continues to work with the chosen strategy - Define deprecation timeline for legacy API (Phase 1: both supported, Phase 2: deprecated warnings, Phase 3: removal)
Recommendation: Specify Option A with dual schemas for clearer separation and better performance.
Context: This is a design-to-development pipeline but lacks automation guidance.
Needed (add new section):
Recommended Workflow:
- Designer updates Figma variables
- Triggers workflow (manual or webhook)
- Export script runs Figma plugin via API
- Validation script checks DTCG compliance
- Terrazzo generates Sass schemas
- Tests run against new schemas
- PR created automatically with changes
Required Tooling:
-
scripts/figma-export.js- Automated Figma token export -
scripts/validate-tokens.js- DTCG schema validation - GitHub Actions workflow (or equivalent CI)
- Token validation rules and test suite
Context: No specification for how to test this pipeline end-to-end.
Needed:
- Unit tests: Token resolution, type validation, reference parsing
- Integration tests: Figma → JSON export, JSON → Sass transformation
- End-to-end tests: Figma → CSS output validation
- Visual regression tests: Component rendering with tokens, theme switching
- Contract tests: DTCG schema compliance, API stability checks
Document test coverage expectations and provide example test cases.
Context: Spec is implementation-focused but lacks practical usage guidance.
Needed:
- Step-by-step workflow: "Adding a New Component Token"
- Troubleshooting guide with common issues:
- Token not resolving → Check reference syntax
- Wrong theme value → Verify mode configuration
- Build failing → Validation tool usage
- Tooling ecosystem recommendations:
- VS Code extension for token autocomplete
- Figma plugin usage guide
- CLI tools for validation/migration
Context: The Sass schema examples show $extensions.modes (e.g., dark mode values), but the specification doesn't explain how these modes translate to actual CSS output.
Needed:
- Define how mode values in
$extensions.modesare converted to CSS - Specify the CSS generation strategy:
-
Option A: Generate separate CSS variable sets per theme (e.g.,
[data-theme="dark"]) -
Option B: Generate media query-based variables (e.g.,
@media (prefers-color-scheme: dark)) -
Option C: Generate multiple CSS files (e.g.,
theme-light.css,theme-dark.css)
-
Option A: Generate separate CSS variable sets per theme (e.g.,
- Document how the
tokensmixin should handle mode-aware tokens - Provide examples showing:
- Input: Sass schema with modes
- Output: Generated CSS with theme selectors/media queries
- Clarify if modes are theme-exclusive or if other mode types (size, density) use different mechanisms
Example to document:
// Input schema
$button: (
background: (
idle: (
$type: 'color',
$value: '#2D6AE3',
$extensions: (
modes: (
dark: '#5B8DEF'
)
)
)
)
);
// Output CSS (Option A example)
:root {
--button-background-idle: #2D6AE3;
}
[data-theme="dark"] {
--button-background-idle: #5B8DEF;
}Context: Lines 424-427 state that DTCG reference strings (e.g., {colors.primary.500}) are "passed through to existing Ignite theming helper functions," but these functions and their behavior are not defined.
Needed:
- Document the reference resolution strategy:
- Which Ignite UI helper functions handle reference resolution?
- How do they parse DTCG reference syntax
{collection.path.to.token}? - Do they expect primitives to be loaded as Sass variables? CSS variables? A lookup map?
- Define the resolution algorithm:
- Parse reference string to extract collection and path
- Look up the referenced token in [specify data structure]
- Return resolved value or [error handling]
- Specify error handling:
- What happens when a reference can't be resolved?
- Should build fail or use fallback value?
- How are circular references detected and handled?
- Clarify the primitive collection loading strategy:
- If primitives aren't consumed from DTCG in Phase 1, how are they made available for reference resolution?
- Are they loaded from existing Sass palette definitions?
- Document the bridge between new DTCG references and existing palette system
Example to document:
// How does this:
$value: '{colors.primary.500}'
// Get resolved to:
$resolved: #2D6AE3 // or var(--ig-colors-primary-500) ?
// Document the resolution function signature:
@function resolve-reference($reference-string, $context) {
// Implementation details needed
}Context: Line 302 mentions "enriched token objects (with $extensions.alias where applicable)" but the enrichment process—how the Figma export JSON and the hand-written alias map are merged—is never defined.
Needed:
- Define where enrichment happens in the pipeline:
- Is it a Terrazzo plugin responsibility?
- A pre-processing script before Terrazzo runs?
- Done at Sass compilation time?
- Document the enrichment algorithm:
- Load DTCG tokens from Figma export (
components.json) - Load legacy alias map (
aliases.json) - For each token in DTCG:
- Look up token path in alias map
- If found, inject
$extensions.aliasproperty - Write enriched token to [output location]
- Load DTCG tokens from Figma export (
- Specify data flow:
Figma Export (components.json) + Alias Map (aliases.json) ↓ [Enrichment Process - DEFINE THIS] ↓ Enriched Tokens ↓ Terrazzo Transformer - Clarify file structure:
- Does enrichment create new files or modify existing ones?
- Are enriched tokens cached?
- How is the enrichment triggered in the build process?
Example to document:
// enrichment script (conceptual)
const figmaTokens = loadJSON('components.json');
const aliasMap = loadJSON('aliases.json');
const enrichedTokens = enrichTokens(figmaTokens, aliasMap);
// What does enrichTokens() do exactly? Document this.
writeJSON('components.enriched.json', enrichedTokens);Context: The border-radius example (lines 337-350) introduces a complex dimension structure with default, min, max keys, but this structure is never explained in the Token Metadata or Base Values sections.
Needed:
- Document when to use simple dimension vs. grouped dimension structure
- Add to "Base Values" section (after line 143):
-
Simple Dimension: Single value tokens (spacing, font-size, etc.)
{ "$type": "dimension", "$value": { "value": 16, "unit": "px" } } -
Grouped Dimension: Tokens requiring constraint values (border-radius with min/max)
{ "$type": "dimension", "$value": { "default": { "value": 4, "unit": "px" }, "min": { "value": 0, "unit": "px" }, "max": { "value": 20, "unit": "px" } }, "$extensions": { "category": "roundness" } }
-
Simple Dimension: Single value tokens (spacing, font-size, etc.)
- Define which
$extensions.categoryvalues trigger grouped structure - Explain the Figma variable setup for grouped dimensions:
- Are these represented as 3 separate Figma variables?
- Or assembled during export from a single variable?
- Show this structure in the "Example JSON Excerpt" section (line 210+)
Context: The specification doesn't establish consistent naming conventions for token properties across the design system, leading to potential confusion and inconsistency (e.g., "background" vs "fill", "foreground" vs "text-color").
Needed:
-
Define a comprehensive naming convention glossary for common token properties:
-
Background colors: Always use
background(notfill,bg, orbackgroundColor) -
Text/content colors: Always use
foreground(nottext-color,color, ortext) -
Border properties: Use
bordernamespace (e.g.,border.color,border.width,border.radius) -
Interactive states: Standardize on
idle,hover,pressed,disabled,focused(notdefault,active,hovered, etc.) -
Sizing variations: Use
small,medium,large(notsm,md,lgors,m,l) -
Spacing/layout: Define conventions for
padding,margin,gap, etc.
-
Background colors: Always use
-
Create a design token vocabulary reference table:
| Semantic Purpose | Standard Token Name | Avoid Using | Example Path |
|---|---|---|---|
| Component background | background |
fill, bg, backgroundColor | button.background.idle |
| Text/icon color | foreground |
text-color, color, text | button.foreground.idle |
| Border color | border.color |
outline, stroke | card.border.color |
| Border thickness | border.width |
border-size, stroke-width | input.border.width |
| Corner rounding | border.radius |
corner-radius, roundness | button.border.radius |
| Drop shadow | shadow |
elevation, box-shadow | card.shadow.default |
| Spacing inside | padding |
inner-spacing, inset | button.padding |
| Spacing between | gap |
spacing, margin-between | stack.gap |
-
Document naming structure rules:
- Use dot notation for hierarchy:
component.property.state - Use lowercase with hyphens for multi-word names:
text-field,drop-down - Place state last in the path:
background.idlenotidle.background - Use singular names:
buttonnotbuttons,shadownotshadows
- Use dot notation for hierarchy:
-
Specify Figma variable naming enforcement:
- How should designers structure variable names in Figma to match these conventions?
- Should there be linting/validation in the Figma plugin to enforce standards?
- Document the transformation if Figma naming differs from output token naming
-
Add examples section showing correct vs. incorrect naming:
Correct:
{
"button": {
"background": {
"idle": { "$type": "color", "$value": "#2D6AE3" },
"hover": { "$type": "color", "$value": "#1E5BBF" }
},
"foreground": {
"idle": { "$type": "color", "$value": "#FFFFFF" }
}
}
}Incorrect (mixed conventions):
{
"button": {
"fill": {
"default": { "$type": "color", "$value": "#2D6AE3" },
"hovered": { "$type": "color", "$value": "#1E5BBF" }
},
"text-color": {
"normal": { "$type": "color", "$value": "#FFFFFF" }
}
}
}- Reference this standard in the "Naming and Grouping Conventions" section (line 75+)