Figma Color Workflows That Scale
Variables, modes, semantic tokens, and the patterns that turn Figma into a real design system runtime — not just a swatch library.
TL;DR
A Figma color setup that works on one screen falls apart at 200 screens, 5 brands, and 3 themes — the fix is a three-layer system (core primitives → semantic aliases → component tokens) using Variables with modes for light/dark. Done well, a brand color update takes 30 seconds; done badly, a week.
A Figma color setup that works for a single screen falls apart at 200 screens, 5 brands, and 3 themes. Here is the structure that scales.
The three layers
Modern color systems are organized into three layers — core, alias, and component:
- Core (primitive) colors — the raw palette.
red.50throughred.900,gray.50throughgray.900, etc. ~10 hues × 11 steps each. - Alias (semantic) colors — purpose-named tokens that reference core values.
text.primary → gray.900,surface.raised → gray.50,border.subtle → gray.200. This is the layer your designers and engineers use. - Component colors — token references at the component level when needed.
button.primary.bg → action.brand. Only create these when truly necessary.
Setting up Variables
In Figma: Local variables → Create collection. Make three collections:Core, Alias, and (optionally) Component. Inside Alias, set each variable to reference a Core variable rather than a hard-coded value.
When you do this, swapping the brand color is a single edit at the Core level — every alias and component that references it updates automatically.
Token contract between design and engineering
Figma Variables become useful at scale only when the engineering contract is explicit. Designers should not hand developers a screenshot of a color library; they should hand over names, values, modes, fallback rules, and ownership.
- Core tokens map to raw color values, such as
brand.red.500 = #C8102E. - Semantic tokens map to product meaning, such as
action.primary.background = brand.red.500. - Mode values define how the same semantic token behaves in light, dark, high-contrast, or brand-specific themes.
- Fallback values define what code should use when a target platform cannot support a future color syntax.
Generate a starter token payload in the design token generator, then use that JSON as the first version of the design-engineering contract.
Modes — light, dark, and beyond
Figma Variables support modes. Create a mode for Light and Dark on your Alias collection. For each alias, set its value per mode:
text.primary→ Light:gray.900, Dark:gray.50surface.canvas→ Light:gray.0, Dark:gray.950border.subtle→ Light:gray.200, Dark:gray.700
Switching a frame to dark mode then becomes a single setting, not a find-and-replace.
Naming that scales
Use a consistent {category}.{purpose}.{state?} pattern:
text.primary,text.secondary,text.disabledsurface.canvas,surface.raised,surface.overlayborder.subtle,border.strong,border.focusedaction.primary.default,action.primary.hover,action.primary.pressed
Accessibility gates inside Figma
Do not wait for QA to discover that a brand color cannot carry text. Add contrast review to the token approval workflow before a variable is published to the shared library.
- Any token used for body text must clear 4.5:1 against its paired surface token.
- Focus rings, input borders, charts, and meaningful icons should clear 3:1 against adjacent colors.
- Error, success, warning, and info states need a non-color signifier: icon, label, underline, pattern, or copy.
- Color modes should be tested in the color blindness simulator before release.
When a pair is close, verify it in the contrast checker and document whether it is approved for normal text, large text, UI chrome, or decorative use only.
From Figma to code
Sync to code via:
- Tokens Studio for Figma — most popular plugin; exports JSON in W3C Design Tokens Community Group format.
- Figma Variables REST API — programmatic access for custom pipelines.
- Style Dictionary — Amazon's transformer that takes token JSON and emits CSS, SCSS, JS, iOS, Android, etc.
Generate the JSON for any color from our token generator.
Example governance rule
A useful rule for mature teams: no component may reference a core color directly. A button can use action.primary.background; it cannot use brand.red.500. That keeps the brand palette flexible while preserving component behavior across themes.
If a designer needs a new color, the request should include the intended semantic role, affected modes, WCAG result, product examples, and engineering export name. That sounds heavy, but it prevents the slow build-up of duplicate reds, nearly identical grays, and one-off chart colors that nobody owns six months later.
The pitfalls to avoid
- Don't reference core colors directly from components. Always go through alias.
- Don't create one variable per use case. A well-designed semantic layer covers most needs without explosion.
- Don't skip mode setup. Even if you don't ship dark mode today, set up the Light mode properly so adding Dark later is painless.
- Don't let designers add ad-hoc colors. Lock the library, require a PR-style review to add a new core color.
Result
Done well, a brand color update takes 30 seconds: open the Core collection, edit one variable, every screen and component updates. Done badly, the same update takes a week of manual replacements and leaves dead colors in the codebase forever.
FAQ
Try the related tools
Apply what you just read with our free converters and color tools.