Hướng dẫn Thực hành

Figma Auto-Layout Components Với Color Tokens

Đọc 9 phút

Auto-layout and color variables are the two features that, combined, transform Figma from a static mockup tool into a genuine design system platform. Auto-layout handles spacing, sizing, and responsiveness. Color variables handle theming, semantic color assignment, and token-to-code parity.

When you build auto-layout components that use color variables — not hardcoded hex values — you unlock a workflow where theme switching happens in one click, component variants are generated automatically, and developer handoff includes tokens that map directly to production code.

This guide covers the architecture, the binding mechanics, responsive token patterns, theme variants, and handoff workflows that make this work at scale.


Component Color Architecture in Figma

The foundation of any token-based component system is a clean separation between what a color is (the primitive) and what a color does (the semantic or component token).

Three-tier token architecture

Tier 1 — Primitive variables: Raw color values. These contain no semantic meaning. They are named by hue and shade level.

blue/50    → #EFF6FF
blue/500   → #3B82F6
blue/700   → #1D4ED8
neutral/100 → #F1F5F9
neutral/900 → #0F172A
red/500    → #EF4444
green/500  → #22C55E

Use ColorFYI's Shade Generator to generate each hue family as a complete 50–950 scale, then enter those values into your primitive collection. ColorFYI's Palette Generator can help you identify harmonically related hues before you commit to your primitive set.

Tier 2 — Semantic variables: Intent-based tokens that alias primitives. These describe purpose, not color. A single semantic collection typically has Light and Dark modes.

background/page       → Light: blue/50       Dark: neutral/900
background/surface    → Light: neutral/100   Dark: neutral/800
background/elevated   → Light: white         Dark: neutral/700
text/primary          → Light: neutral/900   Dark: neutral/50
text/secondary        → Light: neutral/600   Dark: neutral/400
text/disabled         → Light: neutral/400   Dark: neutral/600
interactive/primary   → Light: blue/500      Dark: blue/400
interactive/hover     → Light: blue/600      Dark: blue/300
border/default        → Light: neutral/200   Dark: neutral/700
border/focus          → Light: blue/500      Dark: blue/400
status/error          → Light: red/500       Dark: red/400
status/success        → Light: green/500     Dark: green/400

Tier 3 — Component variables (optional): Component-specific tokens that alias semantic tokens. Add this tier when a component needs local overrides that should not affect the global semantic token.

button/background/default → interactive/primary
button/background/hover   → interactive/hover
button/text/default       → white (or neutral/50)
card/background           → background/surface
card/border               → border/default

Not every team needs the third tier. It adds maintenance overhead in exchange for component-level isolation. Start without it; add it when you find semantic tokens being overridden inconsistently across components.


Variable Binding to Auto-Layout Components

Auto-layout components in Figma are built from nested frames with fill, stroke, and text color properties. Binding color variables to these properties — instead of using hardcoded hex values — is the mechanical step that makes token-based theming work.

Building a button component with variable binding

Start with the component structure:

[Button — Auto-layout, horizontal, 12px horizontal padding, 8px vertical padding]
  ├─ [Icon — 16×16, optional]
  └─ [Label — text layer]

Frame fill binding: 1. Select the outer Button frame 2. In the Fill section of the Design panel, click the color swatch 3. In the Color Picker, switch to the "Libraries" tab (or look for the variable icon) 4. Select the variable button/background/default (or interactive/primary if not using component tier)

The frame's fill is now driven by the variable. When you switch the frame's mode from Light to Dark (by selecting the frame and using the variable mode dropdown), the fill updates to the dark-mode value automatically.

Stroke binding: 1. Add a stroke to the Button frame 2. Click the stroke color swatch 3. Bind to border/default or a dedicated button/border/default variable

Text layer binding: 1. Select the Label text layer 2. In the Fill section, click the color swatch 3. Bind to the appropriate text variable (button/text/default or neutral/50)

Auto-layout color interactions

Auto-layout components often change visual state on hover or press. In Figma, you represent states as component variants. Each variant can have different variable bindings or simply reference the same variable under a different scope.

For a three-state button (Default, Hover, Pressed): - Default variant: frame fill bound to interactive/primary (#3B82F6 in light mode) - Hover variant: frame fill bound to interactive/hover (#2563EB in light mode) - Pressed variant: frame fill bound to a interactive/active variable or the hover variable at reduced opacity

This keeps all state color logic in the token layer — you never hardcode #2563EB into the hover variant. If you rebrand and change blue/600 from #2563EB to a new value, the hover state updates everywhere automatically.

Scoping variables to prevent misuse

When you create component-tier variables, you can restrict their scope in the variable definition:

  • button/background/default → scoped to Fill only
  • button/text/default → scoped to Fill (for text layers, fill = text color)
  • button/border/default → scoped to Stroke only

These scoping settings mean a designer cannot accidentally apply button/background/default to a text color, or button/text/default to a frame background. The variable simply will not appear in the variable picker when the wrong property is being edited.


Responsive Color Token Patterns

"Responsive" for color tokens has two dimensions: responsive to viewport size (colors that shift between mobile and desktop) and responsive to context (colors that adapt to their container's background). Both patterns are achievable with Figma variables.

Context-responsive colors: surface and elevation

Component fills should adapt to the surface they sit on. A card on a page background should use background/surface. A card inside another card (elevated) should use background/elevated. This creates the visual hierarchy of depth.

Structure semantic variables to express this hierarchy:

background/page       Light: #F8FAFC   Dark: #0F172A   (page base)
background/surface    Light: #FFFFFF   Dark: #1E293B   (cards, panels)
background/elevated   Light: #F1F5F9   Dark: #334155   (overlays, tooltips)

When building a card component: - Card frame fill → background/surface - Tooltip inside the card → background/elevated - Page behind the card → background/page

The three backgrounds are visually distinct in both light and dark mode, establishing depth hierarchy without any hardcoded values.

Density variants and spacing-color coordination

Auto-layout properties (padding, gap, radius) often coordinate with color density. A compact variant of a component may use tighter borders and more saturated backgrounds; a comfortable variant may use more whitespace and softer backgrounds.

You can express this with additional semantic token variants:

background/surface/subtle   → Light: #F8FAFC   Dark: #1E293B
background/surface/default  → Light: #FFFFFF   Dark: #1E293B
background/surface/strong   → Light: #EFF6FF   Dark: #1D4ED8

The subtle variant is nearly transparent against the page; the strong variant uses a colored fill. Bind auto-layout variant padding values alongside color variants so compact + strong and comfortable + subtle are packaged together.

Semantic tokens for interactive state density

A hover-interaction token can double as a density signal:

interactive/tint/subtle   → Light: blue/50    Dark: blue/950
interactive/tint/default  → Light: blue/100   Dark: blue/900
interactive/tint/strong   → Light: blue/200   Dark: blue/800

These are used as hover backgrounds for list items — subtle for dense lists, default for standard lists, strong for high-emphasis interactive elements. All three are defined once in the semantic collection; all three adapt to dark mode automatically.


Component Variants by Theme (Light/Dark)

Figma's variable modes are the mechanism for theme variants. Here is the full workflow for a component that correctly switches between light and dark mode.

Setting up the mode switch

Create a wrapper frame (or section) for your component. This frame represents a "themed surface" — a region where a specific mode applies.

  1. Select the wrapper frame
  2. In the Design panel, look for the variable collection name in the sidebar
  3. Click the collection name and choose the mode: "Light" or "Dark"

All descendant layers in that frame that use variables from this collection will resolve to the selected mode's values. This means you can place the same component side-by-side in a Light frame and a Dark frame to see both themes simultaneously — essential for parallel review.

Building a variant set

For a button component with three states and two themes:

Variants property 1 — State: Default, Hover, Pressed, Disabled Variants property 2 — Theme: Light, Dark

This yields 8 variants. In practice, you do not need to build 8 separate variants manually. Build the 4 state variants, all using variable-bound colors. Then create two instances of the component set: one in a Light-mode frame and one in a Dark-mode frame. The variables handle the color difference — you are not creating separate dark mode artwork.

The "Theme" variant property is most useful when you need to expose it to designers consuming the library, so they can switch between light and dark explicitly in their designs. Alternatively, let the mode inheritance from the parent frame handle it automatically.

Testing theme robustness

After building your component, test it by:

  1. Placing an instance in a Light-mode frame — check all states
  2. Placing the same instance in a Dark-mode frame — check all states
  3. Verifying that no layer uses a hardcoded hex value (any hardcoded value will not respond to mode switching)

Use the Layers panel to inspect each layer's fill. Color values that show a variable icon (the token icon) are correctly bound. Values that show a hex code are hardcoded and need to be converted to variable bindings.


Handoff Color Specs to Developers

The goal of variable-bound components is that developer handoff carries token names — not raw hex values — enabling developers to use the same token names in code.

What developers see in Inspect

When a developer opens Figma's Inspect panel on a variable-bound component, they see the variable name alongside the resolved hex value:

Fill: button/background/default (#3B82F6 in Light mode)
Text: button/text/default (#FFFFFF)
Stroke: button/border/default (#E2E8F0)

This is the core of token-based handoff: the developer sees the token name button/background/default, which maps directly to the CSS custom property --color-button-background-default in their codebase.

Exporting variables as tokens

Figma's Variables REST API (available with a paid Figma plan) allows token export. Tools commonly used for this:

Tokens Studio for Figma: A plugin that syncs Figma variables to JSON token files in the W3C Design Tokens Community Group format. These JSON files can be consumed by Style Dictionary to generate CSS custom properties, Tailwind configurations, Sass variables, or Swift/Android color constants.

Figma Variables Export plugins: Several community plugins (Figma Tokens, Variables Exporter) export directly to common formats without requiring a Style Dictionary pipeline.

A typical exported token for interactive/primary (Light mode) looks like:

{
  "interactive": {
    "primary": {
      "$type": "color",
      "$value": "{blue.500}",
      "$description": "Primary interactive element background — buttons, links"
    }
  }
}

The $value uses an alias reference ({blue.500}) rather than a raw hex, preserving the alias relationship in the export.

CSS custom property output

After processing with Style Dictionary, the export becomes:

:root {
  /* Primitive layer */
  --color-blue-500: #3B82F6;
  --color-blue-600: #2563EB;

  /* Semantic layer — Light mode */
  --color-interactive-primary: var(--color-blue-500);
  --color-interactive-hover: var(--color-blue-600);
}

[data-theme="dark"] {
  --color-interactive-primary: var(--color-blue-400);
  --color-interactive-hover: var(--color-blue-300);
}

Components in code then consume semantic tokens:

.button {
  background-color: var(--color-interactive-primary);
  color: var(--color-button-text-default);
  border: 1px solid var(--color-button-border-default);
}

.button:hover {
  background-color: var(--color-interactive-hover);
}

When the design team changes the primitive value of blue/500 in Figma and exports, Style Dictionary regenerates all consuming custom properties. The CSS button styles update without touching any component code — a complete token pipeline from design to production.

Annotation for components without a token pipeline

If your team does not yet have a token export pipeline, provide developers with a color spec annotation on the component:

Layer Token Name Light Value Dark Value
Button background interactive/primary #3B82F6 #60A5FA
Button text text/on-primary #FFFFFF #FFFFFF
Button border border/interactive #2563EB #93C5FD
Hover background interactive/hover #2563EB #93C5FD

Including both the token name and the resolved hex for each mode gives developers everything they need even without automated export.


Key Takeaways

  • Structure color tokens in three tiers: Primitives (raw palette values by hue/shade), Semantic (intent-based aliases with Light/Dark modes), and optionally Component (component-specific tokens aliasing semantics).
  • Bind variables to auto-layout component layers via the Color Picker's Libraries/Variables tab — any layer with a variable binding will respond to mode switching; any hardcoded hex will not.
  • Scope component-tier variables (Fill-only, Stroke-only) to prevent designers from misapplying tokens in incorrect contexts.
  • Context-responsive color uses elevation-based semantic tokens (background/surface, background/elevated) to establish depth hierarchy that works in both light and dark mode.
  • Test theme robustness by placing the same component instance in both a Light-mode and Dark-mode parent frame simultaneously — verify all layers use variable bindings, not hardcoded hex values.
  • Token-based handoff exposes variable names in Inspect, enabling developers to use matching CSS custom property names for a direct design-to-code relationship.
  • Automate token export with Tokens Studio + Style Dictionary to generate CSS variables, Tailwind configs, and platform-specific constants from a single Figma source of truth.

Màu sắc liên quan

Thương hiệu liên quan

Công cụ liên quan