Figma Variables and Modes: A Practical Guide
By Atif Ullah · · 5 min read
On this page
Figma variables changed how design systems work inside Figma. Instead of hardcoded colors and spacing values scattered across components, you define decisions once and reference them everywhere. Add modes, and the same file can switch between light and dark themes, brands, or densities with a single click.
But variables are also easy to get wrong. Without structure, you end up with hundreds of loosely named values that nobody trusts. This guide covers how I set up variables so they stay useful as a product grows.
What variables are for#
Variables store reusable values. Figma supports several types:
- Color — fills, strokes, and text colors.
- Number — spacing, sizing, radius, border width, opacity.
- String — text content, useful for localization or prototyping.
- Boolean — true or false values, mostly for prototyping logic and visibility.
The big advantage over traditional styles is modes. A variable can have different values in different modes, so a single "text primary" variable can be near-black in light mode and near-white in dark mode.
Structure: primitives and semantics#
The most important decision is separating raw values from meaningful ones. I use two main collections.
Primitives collection#
This holds the raw palette and scales: every color shade, every spacing step, every radius. Names describe the value itself, such as "blue/600," "neutral/100," "space/16," or "radius/8."
Primitives have no modes. They're the paint, not the painting. Designers generally shouldn't apply them directly to layers.
Semantic collection#
This holds meaningful tokens that reference primitives. Names describe purpose, such as "text/primary," "surface/raised," "border/subtle," "action/primary," or "status/error."
This collection has modes — light and dark, for example. In light mode, "surface/default" references "neutral/0"; in dark mode, it references "neutral/950." Components only use semantic variables, so switching modes changes everything at once.
Naming rules#
Good names make variables discoverable and predictable:
- Use slashes to create groups. "text/primary" and "text/secondary" appear neatly grouped in the variable picker.
- Name by role, not appearance. "text/secondary" survives a dark theme; "text/gray" doesn't.
- Be consistent in order. Category, then role, then variant or state: "action/primary/hover."
- Keep names short but clear. You'll type and read these names hundreds of times.
Scope your variables#
Figma lets you limit where variables can be applied. A spacing variable shouldn't appear in the color picker, and a text color shouldn't appear as a fill option for frames if you want to prevent misuse.
Setting scopes reduces clutter in the pickers and nudges designers toward using the right variable in the right place. It's a small setting with a big effect on consistency.
Modes for theming#
Modes are where variables become powerful. Common uses include:
- Light and dark themes. The most common use, and the best place to start.
- Brands. One component library, multiple brand palettes.
- Density. Compact and comfortable spacing for different contexts.
- Platforms. Slight sizing differences between web and mobile.
Apply a mode to a frame or page, and every nested layer using those variables updates. This makes it easy to preview the whole product in dark mode or check a component in every brand without duplicating designs.
Spacing and sizing variables#
Number variables are ideal for spacing scales. Define a scale — 4, 8, 12, 16, 24, 32, 48, 64 — as primitives, then bind auto layout gap and padding to them.
Some teams add semantic spacing too, like "space/inset/card" or "space/stack/section." This is useful for larger systems where spacing decisions need to change by context or density mode, but it isn't required for every project.
Typography variables#
You can use number and string variables for font sizes, line heights, weights, and families, then combine them in text styles. This makes it easier to build responsive type scales — for example, larger headings on desktop than mobile — using modes.
Text styles are still the most convenient way for designers to apply typography. Variables underneath them make the system easier to maintain.
Common mistakes#
A few patterns cause trouble repeatedly:
- Applying primitives directly to components. It bypasses theming and makes dark mode inconsistent.
- Creating a variable for every one-off value. Variables should represent reused decisions.
- Mixing naming conventions. Inconsistent names make the picker confusing and searches unreliable.
- Skipping descriptions. A short note on when to use a variable prevents misuse.
- Forgetting to test modes. Every component should be checked in every mode before publishing.
Handoff to code#
Variables map naturally to code tokens. In Dev Mode, developers can see which variable is applied rather than a raw hex value, so they can use the matching token in code.
For the smoothest handoff, keep variable names aligned with the code token names, agree on a single source of truth, and use plugins or the Figma API to sync tokens between Figma and the codebase if your team has the setup for it.
Start small#
You don't need a perfect variable architecture on day one. Start with semantic color variables and a light and dark mode. Add spacing next. Add typography and other modes as the system matures.
The goal isn't to variable-ize everything. It's to make the most important design decisions explicit, consistent, and easy to change — which is exactly what a design system is for.