EduFlow
UI Design with Figma
0%

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.

  1. 1Styles: reusable composites
  2. 2Variables: single values with superpowers
  3. 3Two tiers: primitives and semantics
  4. 4Keeping the picker clean
  5. 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.

Three columns. Primitives teal 700, gray 500 and white feed semantic variables action primary, text secondary and surface default, which are bound to the check button fill, the streak text and the row background. Primitives Semantic Component use teal/700 gray/500 white action/primary text/secondary surface/default Check fill Streak text Row background
Components point at meanings, meanings point at the palette

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.

Further reading

Check your understanding

4 questions

Question 1 of 4

The Done state of the habit row uses the check color teal/700 directly from the primitives collection. Next sprint you add dark mode. What goes wrong?

Question 2 of 4

Which of these belongs in a style rather than a single variable?

Question 3 of 4

What is the main benefit of aliasing color/text/secondary to gray/500 instead of typing #6B7280 into it?

Question 4 of 4

A designer types 15 into a gap field even though a space variable picker is available. What setup change best discourages this?

Practice

Spot the bug

Review Steady's color variables

Here is an export of Steady’s light-mode color variables. {name} means the variable aliases another variable. The kit’s rules: semantic variables alias primitives (never raw values), are named by role (never by appearance), and every text color passes 4.5:1 on white. Select every line that breaks a rule.

Select the line(s) you think are wrong, then check.