Atomize
Actualizado May 12, 202612 min de lectura

How to Build a Design System in Figma (Step-by-Step)

Step-by-step Figma design system: audit, Variables & token layers, core components, docs, team publish, governance, and code sync.

How to Build a Design System in Figma (Step-by-Step)

Build a Figma design system by completing nine steps in order: audit existing UI, create a dedicated library file, define primitive and semantic token layers as Variables, assemble core components that bind to those tokens, govern variants with Component Properties, document inside the file, publish the team library, assign an owner, and export tokens to code. That sequence is not stylistic — each phase depends on the previous one, and the two most expensive failure modes (components built before tokens, libraries without a named owner) both come from skipping earlier steps. Teams that follow the order ship a usable first release in two to four weeks and expand it incrementally from there.

Three-phase design system build process: Foundation (tokens and Variables), Components (auto-layout, variants, library), and Govern (owner, code sync, docs)
Three phases to a production design system — Foundation first, then Components, then Governance. Each phase builds on the last.

The single most common mistake we saw when auditing design systems at Atomize was components built before the token layer existed. A team would spend weeks crafting a thorough component library - careful auto-layout, complete variants, thoughtful documentation - and then attempt to add Variables and Modes on top. At that point every component fill is a hardcoded hex value. The migration is not just tedious; it is a source of regressions, because rebinding fills one component at a time with no automated verification means some fills get missed, and the mismatch only surfaces when a mode switch produces a visually broken component. Tokens-first is not a stylistic preference; it prevents an expensive class of rework.

Step 1: Audit the Current UI

A thorough audit prevents the most expensive design system mistake: discovering undocumented value divergence after components are already built. Without an inventory, teams unknowingly build on a fractured foundation — three near-identical primary buttons, four informal gray shades — and every component they add locks in that inconsistency deeper. At Atomize, audits routinely surface 30–60 distinct color values where teams expected fewer than fifteen. Collect every hex, font size, spacing hack, and border radius from production files before writing a single Variable.

Use a Figma canvas to collect screenshots side by side. A simple spreadsheet counting unique values (how many blues, how many button variants) makes scope visible. Prioritize by blast radius: navigation, forms, and feedback components appear on nearly every screen — stabilize those foundations first.

Step 2: Create the Dedicated Library File

Separating the design system into its own Figma file is the structural decision that makes every subsequent step tractable. When masters live inside product files, the update path breaks the moment a second product team joins — there is no single source to publish from. A dedicated library file with a predictable page structure (Foundations, Components, Patterns, Documentation, Archive) gives every contributor a shared mental model and keeps the publish workflow clean. Without this separation, governance has nothing to govern.

  • Foundations — Variables (tokens), text styles, color styles, effect styles.
  • Components — all published master components, organized by category (Actions, Inputs, Navigation, Feedback, Data Display).
  • Patterns — screen-level compositions and reusable layouts.
  • Documentation — do/don’t frames, anatomy diagrams, spacing callouts, contribution guidelines.
  • Archive — deprecated components held during a migration window before deletion.

Product files stay downstream and consume instances. Never build masters inside a product file; the moment you do, the update path breaks.

Step 3: Define Tokens with Figma Variables

Tokens defined as Figma Variables before any component is built are what make theming, rebranding, and multi-mode layouts achievable without touching component fills. A single-layer approach — components binding directly to raw hex values — works until the first dark-mode request or rebrand, at which point every fill must be manually updated. The two-layer model (primitives for raw scales, semantics for role-based aliases) means a theme flip changes one collection and propagates instantly. At Atomize, we saw teams cut rebrand turnaround from days to under an hour after migrating to this structure. Define primitives first, then semantics, then bind components exclusively to semantics.

Primitive collections

Raw scales with no product meaning: “Primitives — Color” (gray/50–950, blue/100–900, red, green), “Primitives — Space” (4, 8, 12, 16, 24, 32, 48, 64 as Number variables), “Primitives — Radius” (0, 4, 8, 12, 9999). Restrict editing to system owners.

Semantic collections

UI-role aliases: “Semantic — Color” with background/defaultgray/50 (Light) / gray/950 (Dark), text/primarygray/950 / gray/50, interactive/defaultblue/600, interactive/destructivered/600. Components bind to these semantics only — that is what makes theme flips and rebrands survivable without touching a single component.

Typography

Number variables for font size (12, 14, 16, 20, 24, 32) and line height. Pair with text styles for complete presets (body/md, heading/lg) that reference the primitive sizes so changing the base scale propagates automatically.

Step 4: Build Core Components

Components built on top of a complete token layer are the only kind that survive a theme change or rebrand intact. Without tokens in place first, every fill is a hard-coded value — and each one becomes a manual update the moment the brand palette shifts. The core set (Button, Input stack, Selection controls, Surface, Navigation, Feedback, Supporting atoms) covers 80% of product screens; every component uses auto-layout with all fills, strokes, radii, gaps, and padding bound to a Variable. Hard-coded values are where themes break.

  • Button — hierarchy variants (primary, secondary, ghost, destructive); state variants (default, hover, focus, disabled, loading); props for icon and label.
  • Input stack — label, field, hint text, error message as a real form anatomy unit.
  • Selection controls — checkbox, radio, toggle, select/dropdown.
  • Surface — card with configurable padding and optional header/footer.
  • Navigation — top bar and/or side rail depending on your product shape.
  • Feedback — toast, inline alert, banner in all four severities (info, success, warning, error).
  • Supporting atoms — badge, tag, avatar.

The binding step teams most often miss on core components is padding. In Atomize's component audits, fills and strokes get bound to Variables during construction because a wrong color is visually obvious. Padding values get typed in once and never revisited — quietly falling off the token scale as the spacing system evolves. A button with perfect color tokenization and four manually-typed padding values will not respond to a Density mode switch and will produce incorrect CSS output on the first token export. Bind every padding side and gap to a Number Variable before publishing.

Step 5: Variants vs Component Properties

Using Component Properties for booleans and instance swaps instead of multiplying variants keeps the component set small enough to maintain long-term. Variants encode meaningful layout or hierarchy differences — primary vs. ghost is a real structural distinction — but a separate variant for every icon-present / icon-absent combination multiplies the master count without adding design value. In practice, a Button with 4 hierarchy variants and boolean properties for icon, loading, and full-width covers nearly all product needs; the same coverage via variants alone would require 40+ masters. Fewer masters means fewer frames to update when a token or spacing rule changes.

A button with 3 hierarchy variants × 5 state variants = 15 components to keep current. Three variants plus properties is almost always enough.

When to use variants vs component properties

Use caseVariantsComponent properties
Distinct layout or hierarchy level (Primary vs Ghost)YesNo
Show/hide an element (icon, loading state)NoYes (Boolean)
Swappable slot (icon instance)NoYes (Instance swap)
Editable text labelNoYes (Text)
State that changes layout significantlyYesNo
Maintenance costHigh (each variant = separate master)Low

Step 6: Document in the File

In-file documentation is used; wiki documentation is not. When usage guidance, accessibility notes, and do/don’t examples live in a separate Notion or Confluence page, contributors stop consulting them under deadline pressure — the separation adds friction at exactly the moment clarity matters most. Figma’s component descriptions, Variable descriptions, and a dedicated Docs page keep the relevant guidance one click from the component being used. Teams using Atomize report fewer misuse tickets after migrating documentation into the library file itself.

  • Component description — one sentence on purpose; when to use / when not to use; accessibility notes (required ARIA role, keyboard behavior); link to code.
  • Variable description — semantic intent, contrast pairing (e.g. “text/primary on background/default: 7:1 WCAG AAA”), deprecation notice if applicable.
  • Docs page — anatomy diagrams with spacing callouts, do/don’t frames, interaction notes for complex patterns.
  • Frame annotations — use Figma’s measure tools to call out padding, gap, and radius values so developers do not have to guess.

Step 7: Publish the Team Library

Publishing is what converts a well-structured Figma file into a shared system — it is the moment the library becomes consumable by every product team. Until publish, even a perfectly organized file has no leverage across the organization; after publish, instances in product files stay linked and updates surface as library changes consumers can accept in context. Go to Assets (Shift + I), click the library icon, and publish with a clear description of what is included. Every publish without a same-day changelog is a support ticket waiting to happen.

Every publish needs a short changelog: what was added, what changed, what broke and how to migrate. Post it in Slack or Notion the same day. A library update with no communication is a support ticket waiting to happen.

Step 8: Governance and Contributions

A named owner is the single variable that most determines whether a published library stays current or drifts into obsolescence. Without one, contribution requests pile up unreviewed, token renames happen informally, and the library gradually diverges from production — a pattern Atomize has seen repeat across teams of every size. Assign ownership before the first publish, establish a single intake path (one form or Notion template, not ad-hoc Slack requests), and use Figma branches for any change that could break open design work. A lightweight governance model takes an hour to set up and prevents months of drift.

  • Single intake path — one form or Notion template, not ad-hoc Slack requests.
  • Branch risky refactors — token renaming, layout restructures, variant consolidation.
  • Regular pruning — quarterly audit to deprecate unused components with a migration window.
  • Announce same day — Slack or Notion post with every library publish.

Step 9: Connect Tokens to Code

Tokens that exist only in Figma mean engineering maintains a parallel set, and drift between design and code is guaranteed. The token names components reference in Figma must resolve to the same values in the codebase — otherwise the system has two sources of truth and neither is authoritative. The W3C Design Tokens Community Group (DTCG) specification standardizes the token JSON format so exports can feed any DTCG-compatible pipeline without custom parsers. Atomize exports Variables to JSON, CSS custom properties, or TypeScript so the repo imports one artifact that tracks every library release; when the system publishes, the token file updates too.

Mistakes That Undo the Work

  • Components before tokens — theming and rebrand cost multiplies with every hard-coded value.
  • Over-scoping day one — ship tokens plus five components plus a publish, then expand based on real usage.
  • Undocumented components — misuse rate scales with team size and time since publication.
  • No named owner — libraries without a maintainer drift into inconsistency within months.
  • Design-only system — tokens that never reach code mean engineering maintains a parallel set.

Final verdict - Building a Design System in Figma

A Figma design system built in the right order — audit, tokens, components, governance, code sync — compounds with every release rather than accumulating debt. The two failure modes that undo the work are components built without tokens and a library without a named owner; both are sequencing errors, not technical ones. Start with the minimum viable spine (semantic tokens, five core components, published library, named owner, token export), ship it in two to four weeks, and grow it based on real usage. The system is a product; treat it like one.

A first usable release — semantic tokens, five core components, Docs page, published library — typically takes a focused team two to four weeks. Full coverage grows incrementally; plan releases, not a big bang.

Always a published team library for shared work. Duplicating masters breaks the update path and makes every fix a manual operation across every copy.

Figma does not natively export production-ready token files for all stacks. Plugins like Atomize generate structured JSON, CSS, or TypeScript exports from Variables so developers import a real artifact instead of copying values by hand.

For any change that could break open design work: token renaming, layout restructures, or multi-component refactors. Branch, review, merge, publish — same rhythm as a code pull request.

Semantic color and spacing tokens, the five highest-traffic components, in-file documentation, a published library with a named owner, and a token export that reaches the codebase. Everything else grows from that spine.

Ver todo