Section 3 · Components and Systems
Styles vs Variables
18 min4 min readSpot the bug
Lesson at a glance
Decide when a value belongs in a style or a variable, set up Steady’s primitive and semantic color variables with aliases, and bind components to meanings instead of raw hex codes.
- 1Styles: reusable composites
- 2Variables: single values with superpowers
- 3Two tiers: primitives and semantics
- 4Keeping the picker clean
- 5Use both
No video here — just the real thing: a written lesson, runnable examples, a quiz and practice.
Search Steady’s file for the hex code #0F766E and you will find it on check buttons, the primary button, a focus ring, a link and a progress ring, typed in by hand each time. When the brand team asks for a slightly bluer teal, you face the same hunt as in Lesson 3.1, this time for a color. Worse, when dark mode arrives, some of those places need a lighter teal and some do not, and the hex code cannot tell you which.
Styles and variables both put values in one place. They solve slightly different problems.
Styles: reusable composites
A style is a named bundle of visual properties. At the time of writing, Figma has color styles, text styles, effect styles and layout guide styles. You already planned text styles in Lesson 1.3: Headline is a font family, a size, a weight, a line height and letter spacing, all applied in one click.
Styles shine when the value is a composite. A text style is several properties at once. An effect style can hold a stack of two shadows. A color style can hold a gradient or several layered fills. Change the style and every layer using it updates.
Variables: single values with superpowers
A variable holds one raw value. The core types are color, number, string and boolean (Figma has added further types for motion work since). You can bind variables to fills and strokes, corner radius, gap, padding, width and height, opacity, layer visibility, text content and many typography properties.
Three things make variables different from styles:
- Aliasing: a variable can point at another variable of the same type, instead of holding a raw value.
- Modes: a variable can hold a different value per mode, such as light and dark (next lesson).
- Tokens: variables map closely to the design tokens developers use in code, and at the time of writing you can record each variable’s code name for web, iOS and Android so Dev Mode shows it.
Variables live in collections, and slashes in names create groups: color/text/primary sits in the group color/text.
Two tiers: primitives and semantics
The pattern most design systems use, and the one Steady uses, has two tiers.
Primitives are the raw palette, named by what they are: teal/700 = #0F766E, gray/500 = #6B7280, white = #FFFFFF. They have no opinion about where they are used.
Semantic variables are named by what they are for, and alias a primitive: color/action/primary → teal/700, color/text/secondary → gray/500, color/surface/default → white. Components bind only to semantic variables.
Why bother with the middle column? Because meaning and value change for different reasons. The brand team changes teal/700, and every action color follows. Dark mode changes what color/action/primary points at, and only action colors follow, not every teal in the file. Neither change requires touching a single component.
Steady’s numbers get the same treatment: a space group (space/1 = 4 through space/12 = 48, from Lesson 2.3) and a radius group (radius/sm = 8, radius/md = 12). Bind the habit row’s padding to space/3 and space/4, and its corner radius to radius/md.
Keeping the picker clean
Two settings keep people on the system. Scoping limits where a variable is offered: scope space variables to gap and padding, and they stop appearing in the corner radius picker. Hiding from publishing keeps primitives out of the library that other files see, so designers using the kit only find semantic tokens. Both live in each variable’s edit panel at the time of writing.
Use both
Variables did not replace styles. The usual split is: variables for single values (colors, spacing, radius, booleans) because they alias and switch modes; text styles for typography, with their sizes bound to number variables if you need them to change per mode; effect styles for shadows; color styles only for gradients or layered fills. Bind a color style’s fill to a variable and you get the composite’s convenience with the variable’s modes.
With every component pointing at meanings, dark mode becomes a question of what each meaning points at, which is exactly what modes answer next.
Key takeaways
- A style bundles several properties into one reusable composite, such as a text style’s font, size, weight and line height.
- A variable holds one raw value (color, number, string or boolean), can alias another variable, and can change per mode.
- Use two tiers of variables, primitives for the raw palette and semantic tokens for meanings, and bind components only to the semantic tier.
- Text styles, effect styles and multi-fill or gradient color styles still have no single-variable equivalent, so most teams use both systems.
- Scoping and hiding primitives from publishing keep the variable picker short and stop people from reaching for raw values.