Skip to main content
Praveen Manchi
Case Study · Design System Setup & Maintenance

How I Set Up — and Keep Alive — a Multi-Brand Design System

This is my playbook, shown working: how I structure tokens, components, and Figma files from day zero (Setup), automate the path to production (Automate), and run the system as a product long-term (Maintain). Everything below is interactive — a token you edit in Act 01 ripples through every act, exactly like it would in the real pipeline.

Role · Design Systems Lead0 → 1 Setup + Ongoing Ops4 Brands / Modes4 Platforms
TL;DR — 30 seconds
RoleDesign Systems Lead — token architecture, Figma libraries, pipeline design, governance
Setup10-week 0→1 rollout: audit → 3-tier tokens → atomic component library → CI/CD
MaintainWeekly token PR reviews · per-release visual regression in 4 modes · quarterly component audits
ImpactRebrand in <30 min (was 3–5 days) · 0 hard-coded values · 0 regressions during rollout

DESIGN SYSTEM

ARCHITECTURE

P01
SOURCE OF TRUTH

Figma Variables and Modes are the single origin for every design decision — color, space, radius, type.

P02
TOKEN PIPELINE

Tokens Studio exports to W3C DTCG JSON. Style Dictionary transforms and distributes to every platform.

P03
ARTIFACT DELIVERY

One pipeline. Four outputs: CSS custom properties, Tailwind config, iOS Swift, Android Compose.

P04
CONSUMER SURFACES

Web, marketing, mobile, and internal tools consume one versioned package. Zero hard-coded values anywhere.

3-tierToken Architecture
4Platforms Supported
0Hard-coded Values
< 30 minFull Theme Swap
Before

The Problem I Started With

I audited 6 repositories and 47 components before touching anything. Without a shared system, every team had made local decisions — the same "primary blue" existed in 14 different hex values.

Before — Hardcoded
/* Button.css — Team A */
background: #2563EB;
border-radius: 6px;

/* Card.css — Team B */
border-color: #3B82F6; /* different! */
border-radius: 8px; /* different! */

/* Badge.tsx — Marketing */
background: "#1D4ED8" /* different! */
❌ 14 hex values for "brand blue"❌ Manual copy-paste for every theme❌ 3–5 days to repaint for a rebrand❌ No source of truth
After — Token-bound
/* tokens.css — generated */
--color-action-primary: #3B82F6;
--radius-control: 8px;

/* Button.css */
background: var(--color-action-primary);
border-radius: var(--radius-control);

/* Card.css — same token */
border-color: var(--color-action-primary);
✓ 1 token, infinite consistency✓ Rebrand = 1 variable change✓ 142 usages update automatically✓ Figma is the source of truth
My 10-week rollout
01
Discovery
2 weeks · Audit 6 repos, 47 components
02
Token Architecture
1 week · 3-tier model defined
03
Figma Setup
1 week · Variables, Modes, Libraries
04
CI/CD Pipeline
2 weeks · Style Dictionary + GitHub Actions
05
Rollout
4 weeks · Teams migrated, zero regressions
Setup · 01

Three-Tier Variable Architecture

The first thing I set up: Primitives → Semantics → Components. This cascade is what makes everything else possible. Edit a primitive; the graph ripples.

  • brand-500#3B82F6
  • accent-500#F59E0B
  • neutral-900#0B1020
  • neutral-100#F4F6FA
  • space-416px
  • radius-md8px
  • color-surface-primary→ neutral100
  • color-surface-elevated→ neutral100
  • color-text-primary→ neutral900
  • color-action-primary→ brand500
  • color-action-accent→ accent500
  • spacing-inline-sm→ space4
  • radius-control→ radiusMd
  • button-background→ color-action-primary
  • button-text→ color-surface-primary
  • card-background→ color-surface-elevated
  • card-border→ color-action-primary
  • input-border→ color-text-primary
  • badge-background→ color-action-accent
Primitive
brand-500#3B82F6
Semantic
color-action-primary
Component
button-background

Try it Change the color swatch on brand-500 — downstream semantics and components re-render instantly across all four acts.

Setup · 02

Atomic Design · Tokens to Pages

I organize the component library on Brad Frost’s five levels, extended with a subatomic token layer. Each level maps 1:1 to a Figma library location and a code package — so designers and engineers on my teams navigate the same hierarchy.

A00SubatomicDesign Tokens

Not in Brad Frost’s original model — modern systems treat tokens as the particle layer every atom is built from.

brand-500color-action-primaryradius-control
Figma Variables (Primitives → Semantics → Component)Code packages/tokens
A01AtomsBase elements

Smallest usable UI. Every visual property is bound to a semantic token — never a raw value.

ButtonInputBadgeIconLabel
Figma DS · Components / BaseCode packages/react/src/atoms
CTANEW
A02MoleculesSimple groups

Atoms composed into one job. Molecules introduce layout tokens (spacing, stack gaps) but no new colors.

Form rowSearch barCard headerNav item
Figma DS · Components / PatternsCode packages/react/src/molecules
Go
A03OrganismsComplex sections

Standalone sections of an interface. Organisms own responsive behaviour and content slots.

HeaderCard gridCheckout formData table
Figma DS · Components / PatternsCode packages/react/src/organisms
A04TemplatesPage skeletons

Organisms arranged into a page-level structure with placeholder content. This is where modes are QA’d.

Dashboard shellArticle layoutEmpty state
Figma DS · Components / TemplatesCode apps/*/src/layouts
A05PagesReal instances

Templates filled with production content. Pages live in product repos and consume the system — they never define it.

praveenmanchi.art/homeCheckout /paySettings
Figma Product files (consume the Library)Code apps/web · apps/mobile
Buy
Composition rules per level
  • must Atoms bind visual properties to semantic tokens only.
  • must Molecules compose atoms — they add spacing tokens, never new color decisions.
  • must Organisms own layout & responsive rules; content arrives via slots/props.
  • should Templates are the mode-QA surface — review all brand modes here before publish.
  • never Pages define new components — gaps get contributed back down the ladder.
  • note The mental model matters more than the folder names — many 2026 systems ship a flat components/ + patterns/ layout while still enforcing these composition rules.
Why tokens are the subatomic layer

Atomic design predates design tokens — Frost’s 2013 model starts at atoms. Modern component-driven teams add the token layer underneath: change a particle (brand-500) and every atom, molecule, and organism repaints without a single component edit. That’s the property the three-tier cascade in Act 01 guarantees, and it is exactly how the mode switch in the Modes act repaints this entire page.

1 token edit
6 atomic levels repainted
0 component changes
Setup · 03

Live Component Gallery

Every component I build renders from the token graph — no exceptions. Click any component to trace its variable chain.

Setup · 04

Multibrand via Figma Modes

I structure collections so a brand is just a mode. Same component tree · different soul — switching rebinds primitives only, logic is untouched.

Preview · Brand A

Typography and surfaces

The component logic never changed. Only the primitive → semantic bindings did.

All modes simultaneously
Brand A
Typography

Surface & text derived from neutral-900.

NEW
Brand B
Typography

Surface & text derived from neutral-900.

NEW
Dark
Typography

Surface & text derived from neutral-900.

NEW
High Contrast
Typography

Surface & text derived from neutral-900.

NEW
How modes are structured
  • setup Primitives collection → 1 mode. Raw values never fork per brand.
  • setup Semantic collection → modes brand-a · brand-b · dark · hc. Each mode rebinds aliases to different primitives.
  • scope Scope variables (fill, stroke, radius…) so semantics appear only in relevant pickers — and hide primitives from publishing.
  • apply Modes are set per frame or page and cascade — a whole brand preview is one dropdown change.
Plan limits & multi-brand at scale (Schema 2025)
Figma planModes / collection
Starter1
Professional10
Organization20
Enterprise40

For brand portfolios beyond mode counts, Figma’s extended collections(Enterprise) let a child brand collection inherit a published parent and override only brand-specific values — updates flow down automatically.

Automate · 05

CI/CD · Figma to Shipped Pixels

I automated the path from a Figma variable edit to a versioned npm release — no manual handoff anywhere. Click trigger sync to replay — logs stream live.

How a single Figma variable change propagates to every platform in under 5 minutes.

F01
DESIGN
Figma File
VariablesModesLibrary
F02
EXPORT
Tokens Studio
W3C DTCGJSON
F03
COMMIT
GitHub
tokens.jsonPRReview
F04
BUILD
GitHub Actions
style-dictionary.ymlCI
F05
TRANSFORM
Style Dictionary
CSSTailwindSwiftCompose
F06
SANDBOX
Storybook
ComponentsControlsa11yChromatic
F07
CONSUME
Product Surfaces
WebMobileMarketing
01
Figma file
Variables & Modes source of truth
02
Tokens Studio / Variables API
Export plugin
03
design-tokens.json
W3C DTCG format
04
GitHub commit
Diff → PR → merge
05
GitHub Actions
style-dictionary.yml
06
Style Dictionary
Transform · 4 platforms
07
Outputs
CSS · Tailwind · iOS · Android · npm
08
Storybook
Chromatic visual regression · component sandbox
Waiting for trigger…
Tooling notes (2026)
  • format W3C DTCG token spec released its first stable version—2025.10—on October 28, 2025. This establishes the industry-standard JSON format for cross-platform tokens.
  • build Style Dictionary v5 natively supports DTCG 2025.10 (managing the transition to .tokens.json extensions), while Terrazzo (formerly Cobalt UI) provides a streamlined DTCG-native alternative.
  • sync Figma REST API pulls variables programmatically. For compliance and consistency, CI checks like Check Designs validate usage while Tokens Studio handles GitHub PR syncs for team contribution.
  • release Automated versioning via Changesets aligns token releases with semantic versioning: additive changes trigger minor, value tweaks patch, and name changes major releases.
Naming convention
[category]-[concept]-[property]-[state]

color-action-primary-hover
color-text-on-brand
spacing-inline-sm
radius-control

Purpose-driven paths (color-bg-surface-hover) have replaced the older Category/Type/Item taxonomy — the token name should say what it’s for, never what it looks like.

Automate · 06

Design → Storybook → Production

I use Storybook as the airlock between design and production: every component I ship passes through story → test → visual review before any app can consume it.

S01DESIGN
Figma component

Variants + properties published to the Library. Component bound to semantic variables.

VariablesVariantsLibrary
S02STORY
CSF story authored

One story per state. Controls mirror Figma variant properties 1:1. Figma frame embedded via the Designs addon.

CSF 3ControlsDesigns addon
S03TEST
Automated gates

axe-core a11y checks, play-function interaction tests, and Chromatic snapshots across all brand modes.

a11y addonPlay testsChromatic
S04REVIEW
UI review

Chromatic diffs reviewed by design + eng. Visual change must be approved in every mode before merge.

Visual diff4 modesPR gate
S05PUBLISH
Versioned release

Semver npm release of the component package. Storybook deployed as living documentation.

npmsemverDocs site
S06PRODUCTION
Apps consume

Product teams upgrade the package. The story is the contract — what shipped is what was reviewed.

WebMobileMarketing
Visual regression review — what the Chromatic gate looks like
Baseline · main
Continue
New snapshot · your branch
Continue
Diff overlay
Continue

Edit brand-500 or the radius back in Act 01 and this “new snapshot” drifts from its frozen baseline — exactly the diff a reviewer would be asked to approve or deny before merge.

Story anatomy — Button.stories.tsx
Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from '@org/react';

const meta: Meta<typeof Button> = {
component: Button,
parameters: {
design: { // Figma embed
type: 'figma',
url: 'figma.com/file/…?node-id=42',
},
},
};
export default meta;

export const Primary: StoryObj<typeof Button> = {
args: { variant: 'primary', children: 'Continue' },
play: async ({ canvas, userEvent }) => {
await userEvent.click(canvas.getByRole('button'));
},
};

Controls mirror the Figma variant properties, the design parameter embeds the source frame, and the play function turns the story into an interaction test that runs in CI.

Promotion gates
Story exists for every variant and state (hover, disabled, error)
axe-core reports zero violations per story
Play-function interaction tests pass in CI
Chromatic snapshot approved in all brand modes
Docs page auto-generated from args + JSDoc
npm version bumped — breaking changes gated behind a major
1 story = 1 contract
4 modes snapshotted
0 unreviewed pixels in prod

Since Storybook 9, interaction, a11y, and visual checks run as one Vitest-powered test suite; Chromatic’s TurboSnap only re-snapshots stories a change actually affects, and its UI Review step is the designer sign-off gate before merge.

Automate · 07

System Architecture

The four layers I designed to move value from design intent to shipped pixels. Each layer has exactly one responsibility.

P01
SOURCE OF TRUTH

Figma Variables and Modes are the single origin for every design decision — color, space, radius, type.

P02
TOKEN PIPELINE

Tokens Studio exports to W3C DTCG JSON. Style Dictionary transforms and distributes to every platform.

P03
ARTIFACT DELIVERY

One pipeline. Four outputs: CSS custom properties, Tailwind config, iOS Swift, Android Compose.

P04
CONSUMER SURFACES

Web, marketing, mobile, and internal tools consume one versioned package. Zero hard-coded values anywhere.

01 · SOURCE OF TRUTHFigma Foundations🎨 Variables🌓 Modes🧩 Component Lib02 · TRANSFORMTokens Pipeline🔌 REST API⚙️ Style Dict v5📦 W3C json03 · DELIVERYArtifact Publishing🚀 npm Release🎨 Tailwind JS📱 iOS/Compose04 · CONSUMERSProduct Surfaces🖥️ Web Apps📲 Mobile Apps📕 Storybook
Maintain · 08

Figma Setup · Files, Variables, Branches

How I organize files and run every design change day-to-day: a predictable layout + Figma Branches = auditable changes with the same rigour as code.

File structure
📁 DS · Foundations (Published Library)
   ├─ 🎨 Variables
   │   ├─ Primitives      · brand-500, neutral-100, space-4…
   │   ├─ Semantics       · color-surface-primary, spacing-inline-sm
   │   └─ Component       · button-background, card-border
   ├─ 🔤 Type styles
   └─ 🌓 Modes            · Brand A · Brand B · Dark · HC

📁 DS · Components (Published Library)
   ├─ 🧩 Base             · Button, Input, Badge, Chip
   ├─ 🧩 Patterns         · Card, Alert, Form row, Nav item
   └─ 🧩 Templates        · Page shells, empty states

📁 DS · Icons (Published Library)
   └─ 🔣 Icon set (24px base)

📁 DS · Docs
   └─ 📝 Usage, do / don't, accessibility notes
Variables → Components mapping
Component propertyBound variable
Button · Fillcolor-action-primary
Button · Label colorcolor-on-action-primary
Button · Corner radiusradius-control
Card · Backgroundcolor-surface-elevated
Card · Paddingspacing-stack-lg
Input · Bordercolor-border-input

Rule of thumb: components bind to semantics only. Semantics bind to primitives. No component should reference a raw primitive — that's how you keep modes repaintable.

  • devmode Set per-platform Code syntax in the Variable details panel to map Figma variables directly to codebase token names.
  • bridge Use Code Connect UI / CLI to map Figma component props directly to code parameters, surfacing exact imports and production-ready snippets in Dev Mode.
  • multibrand Apply Extended Collections (Enterprise) to inherit a published parent foundations collection and override specific values for brand and sub-product overrides without splitting files.
  • architecture Adopt a Variable-First Architecture, leveraging variable modes to control spacing, sizing, and motion, minimizing complex component variants.
Repository file structure — the code mirror
📁 design-system/                    (monorepo)
   ├─ tokens/                        · source of truth in code
   │   ├─ primitives/                · color.json · space.json · type.json
   │   ├─ semantic/                  · brand-a.json · brand-b.json · dark.json · hc.json
   │   └─ component/                 · button.json · card.json · input.json
   ├─ packages/
   │   ├─ tokens/                    · built output — CSS vars, TS, Swift, Compose
   │   ├─ react/
   │   │   └─ src/
   │   │       ├─ atoms/             · Button, Input, Badge, Icon
   │   │       ├─ molecules/         · FormRow, SearchBar, NavItem
   │   │       └─ organisms/         · Header, CardGrid, DataTable
   │   └─ icons/                     · generated from Figma export
   ├─ apps/
   │   └─ storybook/                 · stories, a11y + interaction tests
   ├─ style-dictionary.config.js     · transform pipeline config
   └─ .github/workflows/tokens.yml   · CI — build, test, publish

The repo mirrors the Figma structure act-for-act: tokens/ matches the three variable collections, packages/react matches the atomic component ladder, and Storybook sits beside them as the review surface. One mental model, two tools.

Figma branch workflow
main
Published · source of truth
branch
feature/button-radius-tweak
edit
Designer makes change · test in sandbox frame
review
Request review · DS team + eng reviewer
merge
Conflicts resolved · squash into main
publish
Library publish · release notes · version bump
Maintain · 09

Governance, Handoff & Real Examples

I run the design system as a product — with owners, a contribution path, and a public changelog. This is the part that keeps it alive after launch.

Roles
RoleOwns
DS CoreToken architecture, library publishing, releases
Federated contributorsPatterns from product teams · PRs into DS
Design reviewersApprove visual changes · a11y · cross-brand
Engineering reviewersApprove tokens diff · breaking change flag
Contribution rules
  • must Bind via semantic tokens · never raw primitives.
  • must New components land in a branch with a sandbox frame + cases.
  • must All 4 Modes visually reviewed before publish.
  • should Contrast ratios checked against WCAG 2.2 AA.
  • should Breaking changes bump the major version in the token package.
  • never Hard-code hex values inside components.
Dev handoff checklist
Component published to Figma Library with variants + properties
Token package v-bumped on npm · changelog entry
Storybook story + controls for each variant
A11y notes in the component doc (role, keyboard, focus order)
Visual regression snapshot committed
Breaking change? → migration guide linked in release notes
Use case 01
Pushing a color change across the system
  1. Brand asks: brand-500 should shift from #3B82F6 to #2D6AE0.
  2. Designer creates branch brand/primary-refresh in Figma.
  3. Only one primitive value is updated — brand-500.
  4. Sandbox frame auto-updates every button, card border, focus ring.
  5. Dark + High-Contrast modes reviewed in the same branch (they may shift too).
  6. Merge → library publishes → CI extracts tokens → PR opened in @org/design-tokens.
  7. Apps upgrade package; no component code changes needed.
1 variable touched
0 component files changed
142 usages repainted automatically
Use case 02
Running a component audit
  1. Quarterly cadence · every Library component inventoried.
  2. Pull usage data from Figma via REST API + plugin (instance counts per file).
  3. Flag components: healthy (>20 uses), stale (5–20), orphan (<5).
  4. Check each for raw-hex leaks and missing variants (hover, disabled, error).
  5. Produce a scorecard — publish to the DS Docs page.
  6. Orphans → deprecate with 1-release warning; stale → review with owning team.
Q2 audit scored 47 components
6 deprecated safely
11 upgraded to semantic tokens
Maintain · 10

Accessibility · Built Into the System

I treat WCAG 2.2 AA as a token constraint, not an afterthought — contrast is enforced at the primitive level and re-checked in CI, never patched in components.

Contrast ratios by mode
ModeText/SurfaceRatioWCAG AA
Brand Aneutral-900 / neutral-10015.3:1PASS
Brand Bneutral-900 / neutral-10014.8:1PASS
Darkneutral-900 (light) / neutral-100 (dark)13.1:1PASS
High Contrast#FFF / #00021:1PASS
Compliance & Perceptual Contrast (WCAG 2.2 vs. APCA)
  • compliance WCAG 2.2 AA serves as the legal compliance standard (ADA / European Accessibility Act), mandating strict color contrast ratios (e.g. 4.5:1 / 3:1) and visible focus indicators.
  • perceptual Internal token checks evaluate contrast using APCA (Advanced Perceptual Contrast Algorithm) to ensure real-world readability based on font weight, size, and background context.
  • token color-focus-ring maps to a 2px solid brand-500 line with 2px offset, satisfying the WCAG 2.2 focus appearance criteria.
  • rule All interactive components expose :focus-visible via focus-ring token. Tab order strictly follows the semantic DOM tree.
  • never Override focus-visible with outline: none without providing a token-bound focus indicator.
A11y gates in the CI/CD pipeline
01
Token lint auto
No primitive referenced directly in a component token
02
Contrast check auto
style-dictionary plugin runs ratio check on every semantic/surface pair
03
Storybook a11y addon auto
axe-core runs on every story in CI
04
Design review manual
Figma branch reviewer verifies 4 modes visually before publish
Maintain · 11

Impact & What I Learned

The system pays for itself on the first rebrand — but the real product is the operating rhythm that keeps it healthy after launch.

< 30 minFull rebrand (was 3–5 days)
142Usages repainted from 1 token edit
0Hard-coded values across 6 repos
0Visual regressions during rollout
How I maintain it — the operating rhythm
Weekly
  • Triage contribution requests from product teams
  • Review token PRs — semantic naming + a11y contrast
  • Office hours: unblock teams adopting components
Per release
  • Chromatic visual review in all 4 brand modes
  • Changelog entry + semver bump via Changesets
  • Migration guide if anything breaking ships
Quarterly
  • Component audit — healthy / stale / orphan scorecard
  • Deprecation cycle with 1-release warning
  • A11y re-check of every semantic surface pair
What I learned
The semantic layer is the contract

Naming workshops in week 1 saved months of renames. Teams argue about hex values; they align on purpose.

Automation is adoption

Teams didn’t migrate because of a mandate — they migrated because the pipeline made tokens easier than hard-coding.

Governance beats tooling

Contribution rules and quarterly audits kept the system from becoming a component dumping ground.

Treat it as a product

Versioned releases, a changelog, and migration guides earned engineering trust faster than any design review.

Bring this to your team

Everything on this page is how I actually work: audit first, architect the tokens, automate the pipeline, then run the system as a product. If your team is starting a design system — or rescuing one — I’d love to talk.

Get in touch →
State persists across acts — the primitive you edited in Act 01 is still powering the atomic ladder, the mode previews, the sync packet, and the Chromatic diff above.