figma guide
Figma Color System: Semantic Tokens, Palettes, and Modes That Do Not Break
Build a Figma color system with base palettes, semantic tokens, light/dark modes, and contrast checks—so components stay themeable and handoff stays consistent.
- Published
- Updated
- May 29, 2026
- Read time
- 5 min
- Level
- Intermediate
Quick answer
A Figma color system has two layers: primitive palettes (brand blues, neutrals, status reds) and semantic tokens (surface/default, text/primary, border/subtle) that components actually use. Create primitives as color variables, alias semantics to primitives, then add modes (Light, Dark, High contrast) on the semantic collection—not on every button layer. Components bind to semantic tokens only; marketing one-offs are the rare exception. Validate contrast before publish, and pair this guide with variables & modes, dark mode workflow, and accessibility plugins. Start from the Figma guides hub if you are new to libraries.
Who this is for
- Design system owners defining the first shared color collection.
- Product designers tired of
#F5F5F5forks on every card. - Teams preparing Dev Mode handoff where CSS must map cleanly to token names (Dev Mode checklist).
Primitives vs semantic tokens
| Layer | Examples | Who uses it |
|---|---|---|
| Primitive | blue/500, gray/100, red/600 | System designers only |
| Semantic | surface/raised, text/secondary, border/focus | All product components |
| Component-specific (avoid) | button-primary-bg | Only when truly unique |
Verdict: if a product designer picks blue/500 for a card background, you will not ship dark mode without pain. They should pick surface/raised.
Build the primitive palette
Step 1: Choose scales
Most systems need:
- Brand — 5–9 steps (50–900 naming or 100–900)
- Neutral — 8–12 steps for surfaces and borders
- Status — success, warning, error, info (4–5 steps each, or single + background pair)
Step 2: Create color variables
- Open your library file (file organization guide).
- Local variables panel → create collection
primitive. - Add variables
color/blue/500,color/gray/100, etc. - Paste hex from brand guidelines; document source of truth on the cover page.
Step 3: Sanity-check ramps
| Check | Why |
|---|---|
| Neighboring steps are visually distinct | Prevents hover states that look identical |
| Text gray on white passes contrast | Avoids retrofitting semantics later |
| Status colors work on both white and tinted surfaces | Error text on error background is a common fail |
Use accessibility plugins on text/primary against surface/default early—not after 200 screens.
Semantic tokens and aliasing
Naming pattern
Use category / role / emphasis:
color/surface/defaultcolor/surface/raisedcolor/text/primarycolor/text/disabledcolor/border/subtlecolor/border/focuscolor/icon/secondary
Alias primitives
In the semantic collection, set each variable to alias a primitive (e.g. surface/default → gray/50 in Light mode). When brand blue shifts, you update one primitive, not forty screens.
Comparison: color styles vs variables (2026)
| Approach | Best for | Limitation |
|---|---|---|
| Variables + modes | Theming, Dev Mode token names | Learning curve for aliases |
| Legacy color styles | Older files | Weak mode story; migrate when touching file |
| Local fills | Exploratory sketch | Do not ship |
Deep dive on modes: variables & modes designer-first.
Light, dark, and brand modes
- Keep primitives mode-free or duplicate only when brand truly differs per theme.
- Add modes on the semantic collection:
Light,Dark(optionalHigh contrast). - For each semantic token, set mode values (dark
surface/defaultaliases a deep neutral, not#000on every layer).
Preview tricks: file mode switcher, prototype flows, and side-by-side frames—see dark mode design in Figma. Do not paint dark UI by manually inverting fills on instances.
Apply tokens to components
| Element | Bind to |
|---|---|
| Card background | color/surface/raised |
| Primary button fill | color/action/primary or color/brand/default |
| Button label | color/text/on-primary |
| Input border | color/border/default |
| Focus ring | color/border/focus |
Publish components from the library; product files swap instances, never copy hex from the primitive panel.
Forms and states: error borders should use color/border/error, not ad hoc red—align with designing forms in Figma.
Color in Dev Mode and code handoff
Engineers need stable token names, not “Rectangle Fill #1A1A1A”.
- Bind all production fills to semantic variables.
- Document mode default on the cover (“App ships Dark; marketing ships Light”).
- When tokens sync to code, align names with repo (
surface.default↔color/surface/default).
For Git/token pipelines, see best dev handoff plugins and design system plugins.
Migration: from hex chaos to tokens
| Phase | Action |
|---|---|
| 1 | Freeze new screens without semantics |
| 2 | Map top 20 fills to semantic tokens |
| 3 | Update library components first |
| 4 | Run swap on product files section by section |
| 5 | Delete unused color styles after QA |
Imported Sketch/Illustrator files often carry raw fills—clean with Illustrator import guide before tokenizing.
Common mistakes
| Mistake | Symptom | Fix |
|---|---|---|
Semantic names that are hex (blue-500 on buttons) | Dark mode breaks | Rename to role-based tokens |
| Too many primitives | Designers grep 400 swatches | Cap ramps; use aliases |
| Modes on primitives only | Components still hard-coded | Modes on semantics |
| Status color as text on same hue background | Fails WCAG | Pair foreground/background tokens |
| Detached instances after rebrand | Random old blues | Re-link library + publish |
FAQ
How many semantic tokens for v1?
20–35 semantics usually cover SaaS UI (surfaces, text, borders, actions, status). Add more when a second product line needs distinct action tokens—not before.
Should icons use text tokens?
Often yes—color/icon/secondary aliased separately so icon-only buttons can diverge from paragraph text without new primitives.
How does this relate to typography color?
Keep text color in semantic tokens; keep font metrics in text styles (typography guide). Avoid encoding color inside text style names unless your system spec requires it.
What about print or CMYK?
Screen tokens differ from print inks—use print checklist for bleed/PDF workflows; do not assume hex variables export to CMYK correctly.
Bottom line
Primitives hold brand; semantics hold meaning; modes hold theme. Components consume semantics only, contrast is checked on real pairs, and Dev Mode shows names engineers can ship. Next steps: dark mode tokens, Dev Mode handoff checklist, and the tutorials hub.
§ Keep reading