Course 3 · Design Systems & Components · Intermediate

Properties, styles, and tokens

You can end up with sixty variants of one button — every combination of size, icon, and state — and a panel no one can navigate, because you modelled with variants what should have been properties.

Read this module through your lens

New to design: this is how you keep a growing system from collapsing under its own combinations.

The combinatorial trap

Variants are so satisfying that beginners use them for everything, and that leads straight into a wall. Model a button’s size (3) times icon-or-not (2) times state (3) as variants and you already have 18; add one more option and it doubles. The properties panel becomes an unnavigable grid, and every new dimension multiplies the work. This is the combinatorial explosion, and it is the classic intermediate failure.

The escape is a distinction. Some choices are mutually exclusive states of one thing — a button is default OR hover OR disabled, never two at once. Those are variants. Other choices are independent options that combine freely — size, whether an icon shows, what the label says. Those should be component properties, not variants. Get this split right and the same button that needed 18 variants needs 3 variants and a handful of properties.

Properties: options without explosion

Component properties let an instance expose adjustable options in the panel without creating new variants. There are a few kinds, and each replaces a whole axis of variants. A boolean property toggles a layer — “show icon?” — instead of doubling your variant count. A text property exposes a label for editing without diving into the layer. An instance-swap property lets you choose which icon or sub-component goes in a slot. An exposed nested property surfaces a child component’s controls on the parent.

The mental model: variants are the states the component can be in; properties are the knobs you turn on any state. Size becomes a property, icon visibility a boolean, the label a text property — and suddenly the component is both more flexible and far simpler, because options multiply additively in the panel instead of multiplicatively in the variant grid.

Styles and tokens: change once, theme everything

The other intermediate leap is getting values out of the components. A button with the colour typed in as a hex value, padding as a magic number, and a font set inline is a button that must be edited by hand to change anything global. Multiply by a real system and a brand tweak or a dark mode becomes days of work.

Styles and variables fix this. A colour style or a colour variable is a named, central value — “brand/primary”, “surface/raised” — that components reference instead of hard-coding. Text styles do the same for type. Variables (design tokens) go further: spacing, radius, and colour become named tokens grouped in collections, and you can swap the whole collection — a light set for a dark set — to re-theme the entire product without touching a single component.

This is also the cleanest bridge to engineering: these tokens are essentially the design tokens the codebase will consume, so a tokenised Figma file is already speaking the build’s language.

Hands-on exercise

Take your button component and refactor it: keep variants only for true states, and convert size and icon-visibility into properties (a size property, a boolean for the icon, an instance-swap for which icon, a text property for the label). Move every colour to a colour variable and the type to a text style. Then build a second variable collection for dark mode and prove you can re-theme the whole thing with one swap. Capture the before/after of the component panel.

The same lesson, a different object

first try

A button modelled with variants for every combination: small/medium/large x icon/no-icon x default/hover/disabled — 18 variants and climbing.

problem

The variant panel is unusable, adding a 'loading' state doubles everything, and the colours are hard-coded hex so dark mode means editing all 18.

fix

Keep variants only for state (3). Make size a property, icon a boolean + instance-swap. Move colours to variables. Dark mode becomes a one-click collection swap; the panel becomes readable.

The failure gallery

Each of these is caught by a quality gate — keep the cheatsheet open while you work.

See the journey

🖼 Before/after of the component panel: a wall of 18 variants vs three states plus clean properties, and a light/dark token swap. screenshot slot · supplementary to the written core
Variants are for mutually exclusive states; component properties (boolean, text, instance swap) are for independent options. Styles and variables (tokens) hold colour, type, and spacing centrally, so one change re-themes everything.

Cheatsheet

Recipe & shortcuts
Independent options -> component PROPERTIES: boolean (show icon?), text (label), instance-swap (which icon). Mutually exclusive states -> VARIANTS (default/hover/disabled). Colour/type/effects -> STYLES. Reusable values (colour, spacing, radius) -> VARIABLES (tokens). Theme by swapping a variable collection (light/dark) instead of editing components.
Failure modes
  • Combinatorial explosion — a variant for every option combination
  • Hard-coded hex colours instead of a colour style/variable
  • Magic numbers for spacing/radius instead of tokens
  • No theming path (light/dark requires editing every component)
  • Properties and variants used for the wrong kind of choice
Key operations
  • Add boolean / text / instance-swap properties to a component
  • Reserve variants for true states
  • Define colour and text styles
  • Define variables (tokens) and theme by collection
Quality gates
  • Are independent options properties, not variant combinations?
  • Do colours and type come from styles/variables, never raw hex?
  • Can you re-theme (e.g. dark mode) by swapping a token collection?
  • Is the component's panel readable, not a wall of variants?
Workflow steps
  • Separate states (variants) from options (properties)
  • Convert options to boolean/text/instance-swap properties
  • Move colours/type to styles and variables
  • Build a second theme by swapping the variable collection
Next module
  • sys_governance — keeping the system consistent and alive as a team uses it.

Reflection card

Active retrieval — answer from memory before re-reading. Saved to this browser.

  • A component that uses properties (boolean/text/instance-swap) for options, variants only for states.
  • Colours and type sourced from styles/variables, no raw hex on the component.
  • A working theme swap (e.g. light/dark) achieved by changing a variable collection.

Next: sys_governance — keeping the system consistent and alive as a team uses it.

Finish — back to Design Systems & Components →