< Go back

Figma Variables: The Complete Guide to Design Tokens in 2026

28/5/2026 · 13 min read

Variables are not just a smarter version of styles. They are the infrastructure that turns a Figma file into a living system — one that can change its entire appearance with a single mode switch.

For most of Figma's history, styles were the closest thing to a design token system the tool offered. Colour styles, text styles, effect styles — useful, but static. They held a single value and they held it forever. Swapping a theme meant updating every style by hand, and the gap between what the designer called a "token" and what the developer received in a handoff was, at best, a naming convention and a prayer.

Variables changed that equation fundamentally. A variable is a named container that can hold different values in different modes, be aliased by other variables, and be scoped to exactly the properties it is meant to govern. A colour called surface/background can resolve to #FFFFFF in light mode and #121212 in dark mode without touching a single component. That is not a style update — that is a design system doing its job.

What Figma Variables Actually Are — And How They Differ From Styles

A style in Figma is a saved property value: a specific hex colour, a specific type ramp entry, a specific shadow. It lives in the file or library it was created in, it applies directly to a layer, and it has exactly one value. When you update the style, every layer using it updates too — which is powerful, but it is still a one-to-one mapping between name and value.

A variable is different in three important ways. First, a variable can hold multiple values — one per mode. A single variable named color/text/primary can store a light-mode value and a dark-mode value simultaneously. Switching the mode on a frame switches every variable in that frame to its alternate value instantly. Second, a variable can be aliased. A semantic variable like color/button/label can point to a primitive variable like color/neutral/white rather than storing a raw hex value — which means changing the primitive ripples through every alias automatically. Third, variables are typed. Colour, number, string, and boolean variables behave differently, can be scoped to specific Figma properties, and surface correctly in the Figma Dev Mode handoff panel.

Styles still have their place — primarily for complex values like typography composites and effects that variables cannot yet express fully. But for any value that might change with a theme, a mode, or a brand switch, variables are the right tool. A mature design system in 2026 uses variables for colour, spacing, border radius, opacity, and component-level toggles, and reserves styles for the composite type definitions that sit on top of them.

Setting Up a Token Hierarchy: Primitives, Semantics, and Components

The most consequential architectural decision in a variable-based design system is the hierarchy. Get it right and the system scales across brands, themes, and product lines with almost no friction. Get it wrong and you end up with hundreds of disconnected variables that are harder to maintain than the styles they replaced.

The three-layer model that has emerged as the industry standard breaks the hierarchy into primitives, semantics, and components. Primitives are the raw values — the complete colour palette, the spacing scale, the type sizes. They are named for what they are, not what they do. color/blue/500, space/4, radius/md. They have no modes; they are the ground truth the rest of the system builds on.

Semantic variables are aliases into the primitive layer, named for their purpose rather than their value. color/text/primary points to color/neutral/900 in light mode and color/neutral/50 in dark mode. space/component/padding-md points to space/4. The semantic layer is where modes live and where the design system communicates intent to both designers and developers. A developer reading color/surface/overlay knows exactly where to use it without needing to look up its hex value.

  • Primitive variables: raw values only, no aliases, no modes. Name them by scale position — color/red/400, space/8, font-size/lg.
  • Semantic variables: always aliases into the primitive layer, always named by intent. These are the tokens developers actually use in code.
  • Component variables: optional third layer for values specific to one component — button height, card corner radius, badge background. These alias into semantics, never directly into primitives.
  • Never skip a layer. A component variable pointing directly to a primitive bypasses the semantic intent layer and makes theming fragile.
  • Keep primitives mode-free. Adding modes to primitives is the most common hierarchy mistake — it collapses semantic meaning into the wrong layer and makes the system impossible to audit.

Component-level variables are the most debated layer. Some teams skip them entirely and wire components directly to semantics. That works well for simple systems but breaks down when individual components need their own density or size variants that do not map cleanly to the shared semantic scale. The pragmatic answer is to add component variables only when a component has more than two or three unique values that are not already expressed by the semantic layer.

Modes and Themes: Light/Dark, Brand, and Density

Modes are what make variables categorically more powerful than styles. A mode is an alternate value set for a collection of variables — flip the mode on a frame and every variable in that frame resolves to its alternate value. The canonical example is light and dark mode, but modes can express anything that needs to shift together: brand themes, accessibility variants, density scales, language-specific typography overrides.

The key constraint to understand is that modes live on collections, not on individual variables. Every variable in a collection shares the same mode definitions. That means collection architecture and mode architecture are the same decision. A single Color collection with light and dark modes works until you need brand-level colour overrides — at which point you either add brand as a second dimension (which Figma does not natively support as nested modes) or you split into separate collections per brand, each with its own light and dark modes.

The practical architecture most teams land on in 2026 uses three to four collections. A Primitives collection with no modes. A Color semantic collection with light and dark modes. A Brand collection that overrides a small subset of semantic colours per brand identity — primary, accent, on-brand surface. A Density or Spacing collection with default, compact, and comfortable modes for products that need to adapt to different screen densities or user preferences.

One underused pattern is the boolean variable as a mode signal. A variable named feature/new-nav/enabled of type boolean can be used in component conditional logic to show or hide layers, effectively making feature flags a first-class design system concept. Design teams that have adopted this pattern can prototype feature-flagged variants directly in Figma without duplicating frames.

Variables in Auto Layout and Spacing

Colour variables get most of the attention, but number variables applied to spacing and sizing are where variables unlock the most day-to-day design system efficiency. Auto layout in Figma accepts variable bindings for gap, padding, min width, max width, and fixed dimensions — which means a component can express its spatial behaviour in terms of the token system rather than hard-coded pixel values.

The practical impact is significant. A card component with space/component/padding-md bound to its internal padding and space/component/gap-sm bound to its content gap can shift from comfortable to compact density by switching the spacing collection mode on its parent frame. No component editing required. The spatial relationships are preserved; only the scale shifts.

For this to work cleanly, the spacing token scale needs to be designed with density in mind from the start. A scale that uses raw pixel multiples of 4 (4, 8, 12, 16, 24, 32, 48) maps well to a compact mode that uses multiples of 3 (3, 6, 9, 12, 18, 24, 36). The ratios are preserved; everything feels intentionally smaller rather than arbitrarily shrunk. Teams that try to retrofit density onto a spacing system designed without modes usually find that the compact values look wrong because the original scale was not built with a consistent ratio.

Corner radius and stroke width are two more properties that benefit from variable binding in auto layout components. A design system with a radius/component/interactive variable can change the rounding character of every interactive element — buttons, inputs, chips — by updating a single value, without touching any component directly. This is the spatial equivalent of a semantic colour token, and it is underused in most design systems that have otherwise moved fully to variables.

Connecting Variables to Design Tokens for Dev Handoff

The gap between Figma variables and production design tokens has closed significantly in 2026, but it has not disappeared entirely. The pipeline from Figma variable to CSS custom property to design token in a code repository still requires deliberate architecture decisions on both the design and engineering side to work without manual intervention.

The naming convention is the most critical alignment point. If the Figma variable is named color/text/primary and the CSS custom property is named --color-text-primary and the Tailwind config token is named text-primary, the three are recognisably the same thing even across toolchains. Teams that let naming drift — using different separators, different capitalisation conventions, or different semantic groupings — end up with a handoff that requires a human translator at every update cycle.

Figma Dev Mode surfaces variables in the inspect panel alongside the raw resolved value. A developer inspecting a button label sees color/text/on-primary next to #FFFFFF — the token name and the fallback value together. That pairing is what makes the handoff work: the developer can implement against the token name and trust that the resolved value is correct for the current mode. For teams using the Tokens Studio plugin, the sync pipeline can go further — exporting Figma variables directly to a JSON tokens file that feeds a Style Dictionary build, producing platform-specific outputs for web, iOS, and Android from a single source of truth in Figma.

  • Align naming conventions early between design and engineering. Slash-separated paths in Figma translate cleanly to hyphen-separated CSS custom property names.
  • Export variable collections from Figma using the REST API or Tokens Studio to generate a W3C Design Tokens JSON file as the canonical handoff artefact.
  • Use Style Dictionary or equivalent to transform the JSON into platform-specific outputs — CSS variables, Swift colour extensions, Kotlin resource files.
  • Document which collection and mode corresponds to which build target. The Color/dark mode in Figma should map explicitly to the prefers-color-scheme: dark media query output.
  • Version the token JSON alongside the codebase. Designers shipping a new token should open a pull request against the token repository, not just update the Figma file.

Scoping and Publishing in Libraries

Variable scoping is one of the most powerful and least understood features in Figma's variable implementation. Scoping lets you restrict which Figma properties a variable can be applied to — a spacing variable can be scoped to gap, padding, and width properties only, making it invisible in the colour picker. This is not just organisational tidiness; it is a guardrail that prevents variables from being misapplied, which in a large team with many designers is the difference between a system that holds its integrity and one that quietly accumulates inconsistencies.

The scoping taxonomy that works best in practice aligns with the three hierarchy layers. Primitive variables are scoped narrowly — a primitive colour is scoped to nothing at all, making it invisible in the variable picker for most properties and forcing designers to use the semantic layer. Semantic variables are scoped to the properties they represent: fill, stroke, text colour, gap, padding. Component variables are scoped to the properties of the specific component they serve, often a single property like corner radius or minimum height.

Publishing is where the library architecture decisions become consequential at scale. Figma lets you publish variables as part of a team library and control which collections are included. The pattern that scales best separates primitive collections from semantic and component collections across different library files. The primitive library is owned by a small core team, changes rarely, and is consumed by the semantic library. The semantic library is the one published to all product teams. Component-level variables live in the component libraries alongside the components themselves. This separation means that a product team can override a semantic variable for their specific brand context without touching the primitive source of truth.

The governance model for publishing matters as much as the technical architecture. Variable changes are silent in Figma — unlike component updates, there is no notification when a subscribed library updates its variables. Teams that have handled this well establish a changelog convention alongside the library: a pinned comment or a linked Notion page that documents every variable addition, deprecation, and value change with a semantic version number. Consumers of the library can then decide when to accept updates and what they need to test when they do.

Conclusion: Variables as the Backbone of a Living Design System

A design system is only as alive as its ability to change. Variables are what give a Figma-based design system the infrastructure to change in one place and have that change propagate everywhere — across components, across modes, across brands, across the handoff to engineering.

The shift from styles to variables is not primarily a technical migration. It is a change in how a design team thinks about the relationship between names and values. Styles said "this layer is this colour". Variables say "this layer has this role, and the colour that expresses that role depends on the context the layer is rendered in". That semantic indirection is what makes the system composable, themeable, and maintainable at scale.

The teams getting the most out of variables in 2026 share a few common traits. They invested in the hierarchy before they invested in the components — a well-designed primitive and semantic layer pays compound interest over time. They aligned naming conventions with engineering before writing a single token, so the handoff works without translation. They used scoping deliberately to make the system self-documenting — a designer who can only see the tokens appropriate for the property they are editing is a designer who applies the system correctly without needing to read a style guide.

If you are starting a new design system or migrating an existing one, the order of operations matters. Start with the primitive colour scale and spacing scale. Map semantics onto them with modes defined before any components are built. Scope everything as you go. Wire the first few components to the semantic layer and see how a mode switch behaves — that first successful theme flip is the moment a design system stops being a collection of assets and starts being infrastructure. Everything built on top of it from that point forward inherits the system's ability to change.

Next article

Figma Auto Layout →

Designing a scalable design system?

Contact me