Skip to content

design tokens(draft)

Simeon Simeonoff edited this page Nov 7, 2025 · 1 revision

Design Tokens Specification: Figma to DTCG to Sass [Draft]

Contents

  1. Overview
  2. Figma Variable Structure and Collections
  3. Exporting Tokens to DTCG JSON
  4. Transforming Tokens to Sass Maps with Terrazzo
  5. Future Specification Improvements

Owned by

Product Design Team

Developer Name:

Designer Name:

Requires approval from

  • Peer Developer:
  • Design Manager: Svilen Dimchevski

Signed off by

  • Product Owner: Radoslav Mirchev | Date:

Revision History

Version Users Date Notes
1 Initial draft Date 07-11-2025

Overview

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

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.

Figma Variable Structure and Collections

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.

Naming and Grouping Conventions

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).

Figma Sample

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.

Primitive vs. Semantic Tokens

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 .

Supported Variable Types

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 .)

Use of Modes for Theming

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.

Preserving References (Aliases)

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 .

Exporting Tokens to DTCG JSON

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, and components.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:
{
  "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.

Token Metadata

Base Values

For each token, the plugin will include the following properties:

  • Type: The $type field 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 $description field 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 $value key will be set to will be true/false).
  • Figma String$type: "string" (the $value is 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.

Mode Values

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:

  1. The collection's defaultModeId determines the token's root $value.
  2. All other modes are added to $extensions.modes keyed by mode name.
  3. Mode names from Figma are transformed to lower case (e.g. "Light" -> "light", "Dark" -> "dark").
  4. If a variable has the same value across all modes, $extensions.modes is omitted.

Alias References

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.

Figma-specific Metadata

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.

Example JSON Excerpt

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).

Transforming Tokens to Sass Maps with Terrazzo

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.

Inputs

The Terrazzo transformer receives:

Component tokens JSON (DTCG)

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)

Legacy schema alias map (hand-written JSON)

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.

Component Sass schema structure (DTCG-shaped)

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.

Type-aware value resolution (resolve-token-value)

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.

Inputs:

  • $node – the leaf map containing $type, $value, $extensions, $description.
  • $path – the component-local path, e.g. ('background', 'idle') or ('border', 'radius').

Behavior (conceptual):

  1. Read $type:
    • "color" – interpret $value according 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
  2. Read $extensions:
    • This grouped value structure keeps all related constraint values together in $value, avoiding confusion with $extensions.modes which 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.
  3. The resolver does not concern itself with legacy schema keys; those are used later when building backwards-compatible structures.

Component CSS variables (tokens mixin)

A tokens mixin is responsible for turning a component schema into component-scoped CSS custom properties.

Signature (conceptual):

/// 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);

Behavior:

  1. Flatten $schema into (path → node) pairs.
  2. 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.
  3. 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 $value fields 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.

Using legacy schema keys (backwards compatibility)

The alias extension captured from the alias map is used to maintain compatibility with existing Ignite schema property names and APIs.

Specifically:

  • 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.

The _token function (optional helper)

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. #2d6ae3 or 4px)

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.


Future Specification Improvements

[!TODO] The following areas need to be addressed in future versions of this specification:

1. Figma Mode to DTCG Mapping Rules

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.defaultModeId determines which value goes into the token's root $value
  • Specify that non-default modes are added to $extensions.modes keyed by mode name (normalized to lowercase)
  • Clarify behavior when a variable has identical values across all modes (omit $extensions.modes?)

2. Phase 1 Scope Boundary (Variables vs Styles)

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

3. Plugin Error Handling and Validation Strategy

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.scopes array for traceability
  • Log all warnings to console and export a validation summary file

4. Terrazzo Configuration Specification

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.js example 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)

5. Legacy Compatibility Implementation Details

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.

6. CI/CD Integration and Automation

Context: This is a design-to-development pipeline but lacks automation guidance.

Needed (add new section):

Recommended Workflow:

  1. Designer updates Figma variables
  2. Triggers workflow (manual or webhook)
  3. Export script runs Figma plugin via API
  4. Validation script checks DTCG compliance
  5. Terrazzo generates Sass schemas
  6. Tests run against new schemas
  7. 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

7. Testing Strategy

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.

8. Developer Workflows and Troubleshooting

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

9. Mode Handling in CSS Generation

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.modes are 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)
  • Document how the tokens mixin 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;
}

10. Reference Resolution Mechanism

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:
    1. Parse reference string to extract collection and path
    2. Look up the referenced token in [specify data structure]
    3. 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
}

11. Token Enrichment Process

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:
    1. Load DTCG tokens from Figma export (components.json)
    2. Load legacy alias map (aliases.json)
    3. For each token in DTCG:
      • Look up token path in alias map
      • If found, inject $extensions.alias property
      • Write enriched token to [output location]
  • 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);

12. Complex Dimension Value Structure

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" }
      }
  • Define which $extensions.category values 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+)

13. Token Naming Conventions and Semantic Standards

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 (not fill, bg, or backgroundColor)
    • Text/content colors: Always use foreground (not text-color, color, or text)
    • Border properties: Use border namespace (e.g., border.color, border.width, border.radius)
    • Interactive states: Standardize on idle, hover, pressed, disabled, focused (not default, active, hovered, etc.)
    • Sizing variations: Use small, medium, large (not sm, md, lg or s, m, l)
    • Spacing/layout: Define conventions for padding, margin, gap, etc.
  • 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.idle not idle.background
    • Use singular names: button not buttons, shadow not shadows
  • 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+)
Clone this wiki locally