Skip to content

Design Tokens ⇄ Figma Variables

Your design tokens live in code (data/themekit.json — colors, radius, spacing, typography, plus the bundled theme presets). Your designers live in Figma. This page is the two-way bridge between them, so both sides share one vocabulary:

  • export_figma_variables — code → Figma. Turn the token catalog into a Figma Variables library your designers theme with.
  • import_figma_variables — Figma → code. Turn a company’s Figma Variables file into a ThemeConfig that re-skins every ThemeKit component.

Together they form a round-trip: a file ThemeKit exported can be imported back with zero loss, and any brand’s file can be adapted with a little mapping.

Figma Variables are typed design tokens (colors, numbers, strings) grouped into collections. A collection can have multiple modes — the classic use is Light / Dark, but a mode is really just “a column of values.” Switch the mode and every variable resolves to that column.

ThemeKit maps onto this exactly:

ThemeKitFigma Variables
A color/spacing/radius tokena Variable
A token category (background.*, spacing)a Collection
The 32 theme presetsmodes of one Brand collection
The token’s name (background.bg-white)the Variable’s codeSyntax

That “presets as modes” idea is the key trick — see below.


Use themekit · export_figma_variables

It reads the token catalog and returns a Figma Variables library in five collections (277 variables total):

CollectionWhat’s in itTypeModes
Brandprimary · secondary · accent · basecolorone per preset (Default, Dark, Dracula, …)
Colorevery resolved token — foreground/*, background/*, text/*, palette/primary/50colorDefault
Radiusthe size scale + the box / field / selector rolesnumberDefault
Spacingthe spacing scalenumberDefault
Typographysize · lineHeight · weight per text stylenumber / stringDefault

The Brand collection carries one Figma mode per theme preset. A designer picks the Dracula mode and the four brand seeds switch — exactly like ThemePreset.named("dracula").apply() does in the app. One file, every brand.

  • model (default) — a clean, tool-agnostic JSON you can feed to a Figma plugin or inspect by hand.
  • format: "figma-rest" — the exact body for Figma’s bulk-write endpoint.
Use themekit · export_figma_variables with format: "figma-rest", collections: ["Brand","Color"]

Then POST it to Figma:

Terminal window
curl -X POST \
-H "X-Figma-Token: $FIGMA_TOKEN" \
-H "Content-Type: application/json" \
--data @variables.json \
"https://api.figma.com/v1/files/<FILE_KEY>/variables"

Filter with collections: [...] to export just what you need.

Every exported variable stores its originating ThemeKit token in codeSyntax (the iOS platform slot). That’s what makes the round-trip lossless (the importer reads it back exactly) and lets Figma Dev Mode show the ThemeKit token beside each value.


Use themekit · import_figma_variables with variablesJson: "<...>", mode: "Dark"

It resolves the brand seeds for the chosen mode and emits a ThemeConfig plus a theme.json:

// imported from Figma — mode "Dark" (lossless via codeSyntax)
Theme.shared.apply(ThemeConfig(primaryHex: "605dff", secondaryHex: "f43098",
accentHex: "00d3bb", baseHex: "1d232a", dark: true))
{ "primaryHex": "605dff", "secondaryHex": "f43098", "accentHex": "00d3bb", "baseHex": "1d232a", "dark": true }

Either shape works:

  1. A real Figma file — pull its variables with GET /v1/files/:key/variables/local and hand in that JSON.
  2. A ThemeKit export — the model from export_figma_variables (the lossless path).

How a seed is resolved (trusted → last resort)

Section titled “How a seed is resolved (trusted → last resort)”
#SourceWhen it winsLossless?
1codeSyntaxthe variable names a brand.<role> token✅ yes
2aliasesyou map the variable name to a role
3name heuristicthe name looks like primary/base/surface

codeSyntax beats a conflicting name. Anything unresolved is reported, never guessed — you’ll see exactly which seed is missing and can supply an alias.

A company that named things their own way just needs a hint:

Use themekit · import_figma_variables with
variablesJson: "<...>",
aliases: { "Brand/500": "primary", "Surface/Canvas": "base" }
  • VARIABLE_ALIAS — if a brand variable points at a primitive (Brand/primary → blue/500), the importer dereferences it across collections and modes to the real color.
  • Mode picking — multi-mode files: pass mode (Light / Dark / a preset name). Omit it and the collection’s default mode is used.
  • Dark inferencedark: true is inferred from the mode name (contains “dark”) or the base color’s luminance, or you can force it.

tokens ──export_figma_variables──▶ Figma Variables (designers theme here)
▲ │
└──────import_figma_variables◀─────────────┘

Because every exported variable carries its token in codeSyntax, a file that went out of ThemeKit comes back with identical seeds — a true lossless loop. A file that started life in someone else’s Figma comes back with a one-time alias map, and from then on it’s lossless too.

  • Multi-brand / white-label — a partner hands you their Figma Variables file; import_figma_variables turns it into a ThemeConfig and every ThemeKit component re-skins to their brand. No code changes.
  • Design ↔ code stay in sync — ship the exported library to your design team so mockups use the exact tokens the app renders; pull their edits back with the importer.
  • Theme authoring in Figma — designers explore brands as modes, then export the winning mode straight into a live ThemeConfig.