Skip to content

Variables

Export the compiled tokens as Figma variables, and update every mode in place as the tokens change.

View source View as Markdown

Mirror’s tokens reach Figma in two halves. Colors, dimensions and the singular typography values become Figma variables, imported with Figma’s own variable import, and the composites a variable cannot hold, meaning text styles and effect styles, go in through a plugin we ship. This page covers the variables half; Styles covers the plugin. Both halves update what is already in the file when you re-run them, and neither ever deletes anything.

Everything below describes the export built from our standard token set. The same commands work against a token set of your own, with the collections read off your config instead of ours; see Custom Tokens for what changes.

Generating the export

Terminal
pnpm mirror tokens
pnpm mirror figma

mirror tokens compiles the token source into .maas/tokens/, and mirror figma reads that compiled output and nothing else, so the two run in this order. The command needs the json platform in options.platforms of mirror.config.ts and stops with an error naming the key without it.

The export is written to .maas/figma/, one directory per variable collection with one DTCG file per mode, plus the styles.json payload the plugin reads. Built from our own token set, that comes out as follows.

.maas/figma/
  color/base.json
  color/dark.json
  dimension/base.json
  typography/base.json
  typography/mono.json
  typography/sm.json
  styles.json

styles.json takes no part in the variable import. It is the one input of the Mirror Styles plugin, and Styles covers what it does.

Which collections and modes come out is stated in figma.collections of mirror.config.ts, and the key is required. Our stock config, which mirror init scaffolds, declares the three collections in the listing above; this is its color entry.

figma: {
  collections: [
    {
      name: 'Color',
      types: ['color'],
      modes: [
        { name: 'Base', targets: ['application'] },
        { name: 'Dark', targets: ['application', 'theme/dark/application'] },
      ],
    },
  ],
}

name is the collection in Figma and the directory its mode files are written into, types names the source $type values that belong to it, and each mode lists the targets it reads. Typography declares Base, Mono and SM modes the same way, which is why the mono theme’s file sits under typography and not under color, and Dimension declares Base alone. A run without the key fails, and the error prints a suggested roster read off your targets, ready to paste into the config. Custom Tokens documents the full shape of the key.

Every value in the files is a resolved literal, with colors converted to sRGB and rem sizes multiplied out to pixels, so no collection depends on another being imported. Each entry includes a description naming the token path and its authored value, so a variable in Figma traces back to the token it came from.

Before anything is written, the command checks that every mode file of a collection holds the identical set of variable names and types, and a mismatch fails the run naming the collection, the mode and the missing names. Figma creates a variable only when it appears in every file a new collection is built from, so a hole in one file would silently drop the variable from all of them. The output directory is cleared and rewritten on every run, so a mode that leaves the config also leaves the disk.

Importing the variables

The mode files go in through Figma’s own variable import rather than through the plugin. A variable is addressed by an internal ID, and every layer and style that uses it points at that ID, so an update has to change values without recreating variables, and Figma’s importer is where that is handled correctly.

To create a collection, open the Variables panel in your Figma file, create an empty collection, and drag all of the collection’s mode files into it together. Each file becomes one mode.

To update after a re-run, right-click the mode, choose Import mode, and pick the regenerated file. Variables are matched by name and type, and their values are updated under the same ID, so everything pointing at them keeps working. Mode names take no part in the matching, so a designer who renames Base to Light in Figma changes nothing about how updates arrive.

To adopt a theme later, import its file as a new mode of the same collection, once.

Names

The variable names are the token paths, slash-joined. Color names drop app.color. and the component segment, since nearly every semantic color lives under it, and they keep default, so the hover and active variables sit next to it in the panel. Everything else drops the leading app. alone.

TokenVariable
app.color.surface.bg.basesurface/bg/base
app.color.component.primary.bg.solid.defaultprimary/bg/solid/default
app.fontSize.surface.display.lgfontSize/surface/display/lg

The import never deletes. A renamed token arrives as a new variable and leaves the old one behind with nothing pointing at it, and removing the orphan is a decision made in Figma rather than by the import.

What a re-run changes

The variables and the text styles split the work. The styles are bound to the variables, so a value-only token change is finished once the affected modes are re-imported, and the plugin only enters when the set of styles itself changes. That second case is covered on Styles; the rows below are the variable half.

ChangeWhat to do
A token value changedRun both commands, then update the affected modes through Import mode.
A theme or breakpoint was addedRun both commands, then import the new file as a new mode of its collection.
A token was renamed or removedNothing is removed in Figma. The old variable stays behind with nothing pointing at it; delete it by hand.

Further reading

  • Styles: the text and effect styles, and the plugin that writes them.
  • Custom Tokens: the same export built from a token set of your own.
  • CLI: the command, and the arguments the build commands share.
  • Configuration: mirror.config.ts, which holds the targets and the figma.collections roster the export reads.