Figma can import design tokens as variables directly: open the Variables view, create a collection and drop a JSON file on it. The file has to be in the Design Tokens Community Group (DTCG) format, and Figma is picky about what it accepts. From Figma's help page on modes:
- Colors must be sRGB or HSL objects (
colorSpace,components,alpha, optionalhex). - Dimensions must be in
px. Anything inremis not imported. - Font families must be a single name as a string. A fallback stack is not supported.
- Numbers are fine, and nested names become folders:
color.primaryturns intocolor/primary.
Composite types like typography and shadow aren't on the list.
Most sites already have their tokens as CSS custom properties, so here is a small script that converts a :root block into a file that follows those rules.
The input
The :root block of Northwind Roasters, a fictional coffee shop site I use for demos. Shortened, but these are the real values:
:root { --color-primary: #c2410c; --color-background: #fffaf3; --font-body: "Hanken Grotesk", ui-sans-serif, system-ui, sans-serif; --text-base: 1.0625rem; --leading-base: 1.6; --weight-base: 400; --space-16: 16px; --radius-lg: 10px; --shadow-sm: rgba(43, 29, 20, 0.08) 0px 1px 3px 0px; --gradient-1: linear-gradient(135deg, rgb(194, 65, 12), rgb(245, 158, 11)); } The full block has 49 variables: 9 colors, 3 font stacks, 5 type sizes with line height and weight each, 13 spacing values, 5 radii, 3 shadows and a gradient.
The script
import { readFileSync } from 'node:fs'; const css = readFileSync(process.argv[2], 'utf8'); const vars = [...css.matchAll(/--([\w-]+):\s*([^;]+);/g)].map(([, name, value]) => [name, value.trim()]); const hexToSrgb = (hex) => { const n = [1, 3, 5].map((i) => parseInt(hex.slice(i, i + 2), 16) / 255); return { colorSpace: 'srgb', components: n.map((c) => +c.toFixed(4)), alpha: 1, hex }; }; const toPx = (v) => { const m = v.match(/^(-?[\d.]+)(px|rem)$/); if (!m) return null; return { value: m[2] === 'rem' ? +m[1] * 16 : +m[1], unit: 'px' }; // Figma only takes px }; const firstFont = (stack) => stack.split(',')[0].trim().replace(/^["']|["']$/g, ''); const tokens = {}; const skipped = []; const put = (path, token) => { const keys = path.split('-'); const group = keys.length > 1 ? keys.shift() : 'misc'; (tokens[group] ??= {})[keys.join('-')] = token; }; for (const [name, value] of vars) { if (/^#[0-9a-f]{6}$/i.test(value)) put(name, { $type: 'color', $value: hexToSrgb(value) }); else if (name.startsWith('font-')) put(name, { $type: 'fontFamily', $value: firstFont(value) }); else if (toPx(value)) put(name, { $type: 'dimension', $value: toPx(value) }); else if (/^-?[\d.]+$/.test(value)) put(name, { $type: 'number', $value: +value }); else skipped.push(name); } console.log(JSON.stringify(tokens, null, 2)); console.error(`converted ${vars.length - skipped.length}, skipped: ${skipped.join(', ')}`); Run it with node css2figma.mjs styles.css > tokens.json. It reads the variables with a regex, which is fine for a :root block of plain values; it doesn't resolve var() references.
What came out
converted 45, skipped: shadow-xs, shadow-sm, shadow-2xl, gradient-1 A few of the converted tokens:
"primary": { "$type": "color", "$value": { "colorSpace": "srgb", "components": [0.7608, 0.2549, 0.0471], "alpha": 1, "hex": "#c2410c" } } "base": { "$type": "dimension", "$value": { "value": 17, "unit": "px" } } "body": { "$type": "fontFamily", "$value": "Hanken Grotesk" } That's 9 colors, 3 font names and 33 numbers: 5 sizes, 5 line heights, 5 weights, 13 spacing values and 5 radii. Every token uses a type Figma lists as supported.
Each step of the conversion:
Colors. Divide each channel by 255: #c2410c is 194, 65, 12, which gives 0.7608, 0.2549, 0.0471. I keep the hex too, since Figma accepts it alongside the components and it's easier to read in a diff.
rem to px. --text-base: 1.0625rem becomes 17px. That multiplies by 16, which assumes the root font size is the default. If the site sets html { font-size: 62.5% }, use 10 instead, or you'll import every size 60% too big. Check getComputedStyle(document.documentElement).fontSize on the site first.
Font stacks. Only the first name survives: "Hanken Grotesk", ui-sans-serif, ... becomes Hanken Grotesk. Figma variables just hold the name, so nothing is lost there that Figma could use.
Shadows and gradients are skipped. In Figma they're effect and fill styles, not variables, so recreate those 4 by hand.
Two things that caught me out
JSON object key order. In the CSS the radii go md, lg, 2xl, 18, full. In the output they came out as 18, md, lg, 2xl, full. JavaScript objects always put integer-like keys first, in ascending order, before any other key, so 18 jumped to the front. The spacing group only has numeric names, so there it happens to look right. If the order in the file matters to you, for diffs or for how the folder reads in Figma, use non-numeric names like r18 or s4.
One name with no group. --space: 4px has no second part, so the script puts it in a misc group. Rename it in the CSS (--space-base) or in the JSON before importing, or you get a lonely misc/space folder.
Importing
- In Figma, open the Variables view and create a new collection.
- Drag
tokens.jsoninto it. Figma creates one mode for the file. - For a dark theme, run the script on the dark
:rootvalues and import that file too: Figma makes one mode per file. A variable is only created if its token is in every file with the same type, so keep the names identical. - To update later, right-click the mode and choose Import mode. Variables with matching names and types get the new values.
Figma lists import as available on Professional, Education, Organization, Government and Enterprise plans.
If you don't have the CSS
All of this assumes you have the site's variables. If you're matching a site you didn't build, you need to read the colors, fonts and sizes off the rendered page first.
I made a Chrome extension, Stylasso, that does that and can write the Figma tokens file directly. Its colors and sizes for this demo site match the script's output above exactly; it also keeps type styles and shadows as composite tokens for Tokens Studio. There's a guide here: website to Figma variables. The script above is enough if you already have the CSS.
Written with help from an AI assistant. The script was run on the demo site's CSS and the output shown is what it printed; the import rules are from Figma's help page.


