Design tokens > Sync design token JSON to Figma Variables
Purpose
Sync design tokens authored in Design Token Format Module JSON in GitLab UI to Figma Variables using the Figma REST API.
Notes:
- Figma API docs will provide temp (24 hour) API keys.
- Some discussion about requirements gitlab-org/gitlab-services/design.gitlab.com#1605 (comment 1756172281)
- Spike #2460 (closed)
- Spike MR !3952 (closed)
Spike Outcome
Spike exploration into adapting Figma's example into GitLab UI !3952 (closed)
Initial findings documented here #2460 (comment 1761636804), summary below:
Findings
- One-way syncing from GitLab -> Figma is preferable as Figma -> GitLab UI doesn't maintain file organisation, instead organised by Figma "Collection"
- Design Token Format Module types require mapping to Figma Variable types
- POST payload transformation into Collections, Variables, Modes, Values (variables for modes)
- GET required to fetch Figma IDs for Collections, Variables, Modes, Values and filter POST payload for updated/added tokens only
- Figma IDs ensure associations in Figma are maintained
- Colors require transformation from hex/rgba to decimal rgba format
- Figma Variable scoping can be achieved with
$extensions
property in design tokens !3952 (comment 1759675759)
Types
$type |
Figma |
---|---|
color |
COLOR |
dimension |
FLOAT |
number |
FLOAT |
string |
STRING |
boolean |
BOOLEAN |
Payload
{
"variableCollections": [{
"action": "CREATE",
"id": "my_variable_collection", // sets a temporary id for the variable collection
"name": "New Variable Collection",
"initialModeId": "my_mode" // sets a temporary id for the initial variable mode
}],
"variableModes": [{
"action": "UPDATE",
"id": "my_mode",
"name": "My Mode", // rename the initial variable mode
"variableCollectionId": "my_variable_collection" // uses the temporary id of the variable collection
}],
"variables": [{
"action": "CREATE",
"id": "my_variable",
"name": "float variable",
"resolvedType": "FLOAT",
"variableCollectionId": "my_variable_collection" // uses the temporary id of the variable collection
}],
"variableModeValues": [{
"variableId": "my_variable", // uses the temporary id of the variable
"modeId": "my_mode", // uses the temporary id of the variable mode
"value": 100
}]
}
Collections
Collections are a Figma concept and aren't explicitly defined in the Design Token Module Format. We could infer a collection based on each design token's $type
(a required property of each design token). This would lead to collections such as "color", "dimension", etc.
An alternative is to infer a collection based on the design token JSON filename. This is the approach in the Figma example variables-github-action-example repo, [collection].[name].[mode].tokens.json
(for example dimension.line_height.default.tokens.json
), this would allow for more arbitrary names to be used for collections, .token.json
filenames have file extension recommendations, however the main trade-off is that prefixes are loose without any linting/enforcement to a particular standard. Custom rules would need to be implemented.
Modes
As with collections, modes aren't explicitly defined Design Token Module Format. We use .dark.token.json
filename extensions to infer modes with style-dictionary to generate separate output (CSS/SCSS/JS/JSON files).
The approach in the Figma example variables-github-action-example repo infers mode from the filename e.g. Product interactions — Completed.Default.json
. Followed the same process in !3952 (closed) with .light.tokens.json
and .dark.tokens.json
for colors, and .default.tokens.json
for line-height design tokens. This may not make sense if we progress with something like .aliases.tokens.json
in !3909 (closed).
Transforms
Color
hex to decimal rgb conversions e.g blue-500
with the hex value #1f75cb
becomes:
{
"r": 0.12156862745098039,
"g": 0.4588235294117647,
"b": 0.796078431372549
}
rgba values for transparency colors t-gray-08
need the same treatment rgba(31, 30, 36, 0.08)
becomes:
{
"r": 0.12156862745098039,
"g": 0.11764705882352941,
"b": 0.1411764705882353,
"a": 0.08
}
Dimensions
Currently we have line-height
design tokens expressed as string values e.g. 12px
. Figma does not support these. We will need to updated to number values e.g. 12
in the design token tokens.json
itself, and ensure that compiled CSS/SCSS/JS output from style-dictionary is maintained. Early testing this seems fine, as dimensions are currently converted to rem
value strings with style-dictionary:
--gl-line-height-12: 0.75rem;
$gl-line-height-12: 0.75rem;
export const GL_LINE_HEIGHT_12 = "0.75rem";
Extensions
"$extensions": {
"com.figma": {
"hiddenFromPublishing": false,
"scopes": [
"TEXT_CONTENT"
],
"codeSyntax": {}
}
}
Workflow
flowchart TD
AA[JSON design tokens] -->|Read .tokens.json files| AB(Flatten design tokens)
AB --> |Flat JSON tokens array| CA(Combine and compare)
BA(GET Figma Variables) --> |Figma Variables IDs| CA
CA --> |Filter unique types from tokens as collections| CB(Update Figma collections)
CB --> |Filter unique modes from tokens| CC(Update Figma modes)
CC --> |Resolve Figma IDs and Types| CD(Update Figma Variables)
CD --> |Compare design tokens to Figma Variables| CE(Existing and new values)
CE --> |Parse colors to RGBA decimal format| CF(Update Figma Variable values for modes)
CF --> |Combine collections, modes, variables, and mode values| CG[POST API payload]
Outcome
After experimentation, it is apparent that the REST API is not capable of the functionality we need to fully sync tokens to Figma. This forum post describes the main issue we encountered. tl;dr: creating aliases with remote variables is not allowed via the REST API due to network constraints.