Genoni Studio

April 23, 2026

Mapping Figma variables to design tokens

A look at how Figma variables and design tokens differ, overlap, and how to set up Figma for easier conversion to code.

Mapping Figma variables to design tokens

At Figma’s Config conference in June of 2023, many of us designer/developer folks had our fingers crossed that support for design tokens would be a first-class feature of Figma. Instead what we got was their “answer to tokens” in the form of Figma Variables. Though initially disappointed, I realized that despite an emerging specification, design tokens was far from fully formed, at that time existing more or less as a concept. It would have been premature to adopt it.

So the question of where to locate the “source of truth” for design tokens was (and is) still an open question. Using a git repository with tools like Tokens Studio and Style Dictionary provides version control and package management options that are standard engineering best practices. But that approach also requires a degree of complexity and management that many small startups don’t want to take on, so using Figma is an attractive, if incomplete, option.

Though there are many Figma plugins that will export variables and styles directly to CSS, JavaScript, Swift, and other code formats, some teams prefer to have more granular control over that conversion. As someone who regularly deals with getting Figma Variables into code — either first to the Design Token spec format or directly to a code implementation — I thought I’d share the Figma settings I use to make this process more predictable. To create the simplified Figma code examples below I used the “Export/Import Variables” plugin, which exports the raw Figma API output of the variables.

Design token vs Figma variable types

Design token types

The W3C Design Tokens Community Group specification defines a standard JSON format for sharing design tokens across tools, platforms, and teams. Each token carries a $type field that tells consuming tools — build systems, style processors, code generators — how to interpret and transform its value. Without types, a value like 16 could be spacing, a font size, an opacity, or a z-index. The type removes that ambiguity and is what makes design tokens portable.

The spec defines 18 types split across two categories. Primitive types map directly to a single scalar value:

PropertytypeSpec link
colorcolorSpec ↗
dimensiondimensionSpec ↗
font-familyfontFamilySpec ↗
font-weightfontWeightSpec ↗
font-sizefontSizeSpec ↗
line-heightlineHeightSpec ↗
letter-spacingletterSpacingSpec ↗
numbernumberSpec ↗
stringstringSpec ↗
booleanbooleanSpec ↗
durationdurationSpec ↗
cubic-beziercubicBezierSpec ↗

And Composite types, which bundle multiple values into a structured token object:

ConcepttypeSpec link
borderborderSpec ↗
typographytypographySpec ↗
shadowshadowSpec ↗
gradientgradientSpec ↗
transitiontransitionSpec ↗
stroke-stylestrokeStyleSpec ↗

Figma variable types

Figma’s variable types are far more limited.

Figma typeResolves to
colorA hex, RGBA, or HSLA color value
numberA unitless numeric value, uses FLOAT in Figma code.
stringA text string
booleantrue or false

Figma variable scopes

To map them to a design token type obviously requires more information. To do that we can mostly rely on Figma’s variable scoping. This feature’s primary purpose is to filter the options displayed in the Figma UI only to those variables that are available for a selected node. For example, this can prevent a designer from applying a color to text that was intended only for use as a background fill.

Figma’s available variable scope options are:

Scope
ALL_SCOPES
TEXT_CONTENT
CORNER_RADIUS
WIDTH_HEIGHT
GAP
ALL_FILLS
FRAME_FILL
SHAPE_FILL
TEXT_FILL
STROKE_COLOR
EFFECT_COLOR
STROKE_FLOAT
EFFECT_FLOAT
OPACITY
FONT_FAMILY
FONT_STYLE
FONT_WEIGHT
FONT_SIZE
LINE_HEIGHT
LETTER_SPACING
PARAGRAPH_SPACING
PARAGRAPH_INDENT

By combining the Figma variable’s resolvedType, one or more of the possible entries in its scopes array, and occasionally the variable name, we can reliably convert Figma variables to a token.

Important notes & warnings

  1. Any designer can change Figma variables and scopes without a review, breaking conversion scripts, or worse, introducing unwanted values in the output. Any changes to variables and their output to code should be reviewed carefully.
  2. A number of Figma variables you’ll create, like duration or cubic-bezier values, are there to provide the design team with control over the value used in code, and are not meant to be used by Figma directly. For these values we intentionally leave the scope empty to avoid surfacing it in the Figma UI. This also tells the converting script to let the value pass through unchanged, unlike dimension tokens that append px.

Mapping primitive types

color

A color value in sRGB space.

Example W3C token

{
  "fg-base": {
    "$type": "color",
    "$value": "#0066cc"
  }
}

Example Figma JSON

{
  "name": "fg/base",
  "resolvedType": "COLOR",
  "valuesByMode": {
    "mode": { "r": 0, "g": 0.4, "b": 0.8, "a": 1 }
  },
  "scopes": ["FRAME_FILL", "SHAPE_FILL", "TEXT_FILL", "STROKE_COLOR", "EFFECT_COLOR"]
}

Convert with:

resolvedTypescopes
COLORFRAME_FILL, SHAPE_FILL, TEXT_FILL, STROKE_COLOR, EFFECT_COLOR

dimension

A length value with a CSS unit — typically px, rem, or em.

Example W3C token

{
  "spacing-md": {
    "$type": "dimension",
    "$value": "16px"
  }
}

Example Figma JSON

{
  "name": "spacing/md",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 16
  },
  "scopes": ["WIDTH_HEIGHT", "CORNER_RADIUS", "GAP", "STROKE_FLOAT"]
}

Convert with:

resolvedTypescopes
FLOATWIDTH_HEIGHT, CORNER_RADIUS, GAP, STROKE_FLOAT

font-family

The name of a typeface or a comma-separated font stack.

Example W3C token

{
  "font-sans": {
    "$type": "font-family",
    "$value": "Inter"
  }
}

Example Figma JSON

{
  "name": "font/family/sans",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "Inter"
  },
  "scopes": ["FONT_FAMILY"]
}

Convert with:

resolvedTypescopes
STRINGFONT_FAMILY

font-weight

A numeric font weight from 100 to 900.

Example W3C token

{
  "font-weight-semibold": {
    "$type": "font-weight",
    "$value": 600
  }
}

Example Figma JSON

{
  "name": "font/weight/semibold",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 600
  },
  "scopes": ["FONT_WEIGHT"]
}

Convert with:

resolvedTypescopes
FLOATFONT_WEIGHT

font-size

A type size value with a unit. Figma stores the raw number; units are implied by context.

Example W3C token

{
  "text-lg": {
    "$type": "font-size",
    "$value": "18px"
  }
}

Example Figma JSON

{
  "name": "text/size/lg",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 18
  },
  "scopes": ["FONT_SIZE"]
}

Convert with:

resolvedTypescopes
FLOATFONT_SIZE

line-height

The vertical spacing between lines of text, expressed as a unitless multiplier or a length.

Example W3C token

{
  "leading-normal": {
    "$type": "line-height",
    "$value": 1.5
  }
}

Example Figma JSON

{
  "name": "text/leading/normal",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 1.5
  },
  "scopes": ["LINE_HEIGHT"]
}

Convert with:

resolvedTypescopes
FLOATLINE_HEIGHT

letter-spacing

The horizontal spacing between characters, typically in em units. Figma stores this as a percentage of font size, so -0.02em is stored as -2. A transform step handles the unit conversion.

Example W3C token

{
  "tracking-tight": {
    "$type": "letter-spacing",
    "$value": "-0.02em"
  }
}

Example Figma JSON

{
  "name": "text/tracking/tight",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": -2
  },
  "scopes": ["LETTER_SPACING"]
}

Convert with:

resolvedTypescopes
FLOATLETTER_SPACING

Note that letter-spacing Figma variables must be defined as a number. A STRING variable with a percentage can’t be applied as a letter-spacing variable.

number

A raw unitless number — opacity, z-index, scale factors, and similar values that don’t carry a CSS unit.

Example W3C token

{
  "opacity-disabled": {
    "$type": "number",
    "$value": 0.4
  }
}

Example Figma JSON

{
  "name": "opacity/disabled",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 0.4
  },
  "scopes": ["OPACITY"]
}

Convert with:

resolvedTypescopes
FLOATOPACITY

string

An arbitrary text value that isn’t a color, font family, or numeric.

Example W3C token

{
  "brand-name": {
    "$type": "string",
    "$value": "Genoni Studio"
  }
}

Example Figma JSON

{
  "name": "brand/name",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "Genoni Studio"
  },
  "scopes": ["TEXT_CONTENT"]
}

Convert with:

resolvedTypescopes
STRINGTEXT_CONTENT, FONT_FAMILY

Strings with empty scopes can be used to pass through values unchanged, like a duration value of “300ms”.

boolean

A true/false flag, used in Figma primarily to toggle layer visibility per mode.

Example W3C token

{
  "show-divider": {
    "$type": "boolean",
    "$value": true
  }
}

Example Figma JSON

{
  "name": "show/divider",
  "resolvedType": "BOOLEAN",
  "valuesByMode": {
    "mode": true
  },
  "scopes": []
}

Convert with:

resolvedTypevaluesByMode
BOOLEANmode

duration

A time value for animation and transition timing. Figma has no motion scope — a FLOAT can store the raw number but won’t bind to any animation property.

Example W3C token

{
  "duration-fast": {
    "$type": "duration",
    "$value": "150ms"
  }
}

Example Figma JSON (no motion scope)

{
  "name": "duration/fast",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "150ms"
  },
  "scopes": []
}

Convert with:

name containsresolvedTypescopes
“duration”STRING[empty]

cubic-bezier

A bezier curve defined by four control points [x1, y1, x2, y2] describing an easing function. Figma has no motion scope and no way to bind this to animation properties.

Example W3C token

{
  "easing-out": {
    "$type": "cubic-bezier",
    "$value": [0, 0, 0.58, 1]
  }
}

Example Figma JSON (no motion scope)

{
  "name": "easing/out",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "0, 0, 0.58, 1"
  },
  "scopes": []
}

Convert with:

name containsresolvedTypescopes
“easing”STRING[empty]

Mapping composite types

border

A shorthand combining color, width, and style. Split into two Figma variables; the style value is expressed separately via stroke-style.

Example W3C token

{
  "border-default": {
    "$type": "border",
    "$value": {
      "color": "#e2e8f0",
      "width": "1px",
      "style": "solid"
    }
  }
}

Example Figma JSON

{
  "name": "border/color/base",
  "resolvedType": "COLOR",
  "valuesByMode": {
    "mode": { "r": 0.886, "g": 0.91, "b": 0.941, "a": 1 }
  },
  "scopes": ["STROKE_COLOR"]
}
{
  "name": "border/width/base",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": {
    "mode": 1
  },
  "scopes": ["STROKE_FLOAT"]
}

Convert with:

resolvedTypescopes
COLORSTROKE_COLOR
FLOATSTROKE_FLOAT

typography

A complete text style bundling family, size, weight, line height, and letter spacing. Decompose into five separate Figma variables; Text Styles can then reference them.

Example W3C token

{
  "text-heading-xl": {
    "$type": "typography",
    "$value": {
      "fontFamily": "Inter",
      "fontSize": "48px",
      "fontWeight": 700,
      "lineHeight": 1.1,
      "letterSpacing": "-0.03em"
    }
  }
}

Example Figma JSON

{
  "name": "heading/xl/family",
  "resolvedType": "STRING",
  "valuesByMode": { "mode": "Inter" },
  "scopes": ["FONT_FAMILY"]
}
{
  "name": "heading/xl/size",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 48 },
  "scopes": ["FONT_SIZE"]
}
{
  "name": "heading/xl/weight",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 700 },
  "scopes": ["FONT_WEIGHT"]
}
{
  "name": "heading/xl/line-height",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 1.1 },
  "scopes": ["LINE_HEIGHT"]
}
{
  "name": "heading/xl/letter-spacing",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": -3 },
  "scopes": ["LETTER_SPACING"]
}

Convert with:

resolvedTypescopes
STRINGFONT_FAMILY
FLOATFONT_SIZE
FLOATFONT_WEIGHT
FLOATLINE_HEIGHT
FLOATLETTER_SPACING

shadow

A drop or inner shadow defined by offset, blur, spread, and color. The color feeds a Figma Effect; the numeric values must be mapped manually or via a sync tool.

Example W3C token

{
  "shadow-md": {
    "$type": "shadow",
    "$value": {
      "offsetX": "0",
      "offsetY": "4px",
      "blur": "8px",
      "spread": "0",
      "color": "#00000026"
    }
  }
}

Example Figma JSON

{
  "name": "shadow/md/offset-x",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 0 },
  "scopes": []
}
{
  "name": "shadow/md/offset-y",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 4 },
  "scopes": []
}
{
  "name": "shadow/md/blur",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 8 },
  "scopes": []
}
{
  "name": "shadow/md/spread",
  "resolvedType": "FLOAT", // "number"
  "valuesByMode": { "mode": 0 },
  "scopes": []
}
{
  "name": "shadow/md/color",
  "resolvedType": "COLOR",
  "valuesByMode": {
    "mode": { "r": 0, "g": 0, "b": 0, "a": 0.15 }
  },
  "scopes": ["EFFECT_COLOR"]
}

Convert with:

nameresolvedTypescopes
“shadow” & “offset-x”FLOAT
“shadow” & “offset-y”FLOAT
“shadow” & “blur”FLOAT
“shadow” & “spread”FLOAT
“shadow”COLOREFFECT_COLOR

Note you could use a single STRING to define most of this — "0, 4, 8, 0" — but it would be incomplete because the shadow takes in a color; you’d have to define that separately. Unlike with easing, I prefer to create a variable for each part.

gradient

A color stop list defining a gradient fill. Figma has no gradient variable type. Note that if transparency is needed, raw hex codes with transparency values must be used to specify the stops.

{
  "gradient-base": {
    "$type": "gradient",
    "$value": [
      { "color": "#0066cc", "position": 0 },
      { "color": "#00aaff", "position": 1 }
    ]
  }
}

Simplified example Figma JSON of a gradient color style.

{
  ...
  "name": "gradient/base",
  "type": "PAINT",
  "paints": [
    {
      "type": "GRADIENT_LINEAR",
      "gradientStops": [
        {
          "color": {
            "r": 1,
            "g": 1,
            "b": 1,
            "a": 1
          },
          "position": 0,
        },
        {
          "color": {
            "r": 0.6000000238418579,
            "g": 0.6000000238418579,
            "b": 0.6000000238418579,
            "a": 1
          },
          "position": 1,
        }
      ],
    }
  ]
  ...
}

In this case you can look for PAINT and GRADIENT_LINEAR and use the gradientStops to generate the token. However, you may have other properties to convert like gradientTransform and opacity values.

transition

Combines duration, easing, and delay into a single animation transition token. Figma has no variable types for motion — this token has no Figma equivalent.

Example W3C token

{
  "transition-base": {
    "$type": "transition",
    "$value": {
      "duration": "200ms",
      "timingFunction": [0.4, 0, 0.2, 1],
      "delay": "0ms"
    }
  }
}

Example Figma JSON

{
  "name": "transition/base/duration",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "200ms"
  },
  "scopes": []
}
{
  "name": "transition/base/timing-function",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "0.4, 0, 0.2, 1"
  },
  "scopes": []
}
{
  "name": "transition/base/delay",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "0ms"
  },
  "scopes": []
}

stroke-style

Describes the dash pattern and line cap of a stroke. Figma has no variable scope for dash arrays or line caps — this token is code-only.

Example W3C token

{
  "stroke-dashed": {
    "$type": "stroke-style",
    "$value": {
      "dashArray": ["4px", "4px"],
      "lineCap": "round"
    }
  }
}

Example Figma JSON

{
  "name": "stroke/dashed/dash-array",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "4px, 4px"
  },
  "scopes": []
}
{
  "name": "stroke/dashed/line-cap",
  "resolvedType": "STRING",
  "valuesByMode": {
    "mode": "round"
  },
  "scopes": []
}

Summary

The promise of design tokens is that, eventually, we’ll have a complete design token specification that platforms can adopt, not unlike the way applications support the SVG specification. But until then the process is going to be messy with a lot of custom code, manual mapping, and a fair number of hacks.

Considering a design system?

I help startups big and small plan, establish, and extend their design systems. Reach out and we’ll discuss what’s best for your team.

Schedule meeting Email me
  1. Terms of Service

  2. ·

  3. Privacy Policy

  1. ©2026 Genoni, LLC

  2. ·

  3. San Francisco, California