The term "design system" has been stretched so far that it means something different in every conversation. To a designer it might mean a Figma library. To a frontend engineer it means a component library. To a product manager it means "the reason the settings page looks different from the dashboard." All of these are partially right and entirely insufficient.
A studio-grade design system — the kind we build for clients who will live with it for years — is all three of those things, plus a set of decisions about how they stay synchronized. This post describes what that looks like concretely, in 2026, after eleven systems built and maintained across products ranging from fintech dashboards to e-commerce storefronts.
§ 01What "design system" actually means now
A design system is three things bound together:
- A design token layer — the raw values (colors, spacing, typography, shadows, radii) expressed in a platform-agnostic format.
- A component library — the coded building blocks that consume those tokens and expose a typed API for product teams to compose.
- A documentation and governance layer — the rules, examples, and contribution guidelines that keep the system consistent as the team grows.
The key word is bound. Most teams have pieces of all three. Very few have them connected in a way where changing a token value in one place propagates automatically to Figma, to the codebase, and to the documentation. That propagation is what separates a collection of components from a system.
§ 02Design tokens as the foundation
Tokens are where everything starts. A design token is a named value — color.primary.500, spacing.lg, font.body.size — that represents a design decision. Tokens are the single source of truth for every visual property in the system.
We store tokens in JSON following the W3C Design Tokens Community Group format. From that single JSON file, we generate CSS custom properties, Tailwind theme config, Figma variables, and Swift/Kotlin values for native apps. The generation step runs in CI, so when a token changes in a PR, every platform gets the update automatically.
// tokens/color.json — source of truth { "color": { "primary": { "500": { "value": "#2563eb", "type": "color" }, "600": { "value": "#1d4ed8", "type": "color" } }, "neutral": { "100": { "value": "#f5f5f4", "type": "color" }, "900": { "value": "#1c1917", "type": "color" } } } }
The critical principle: tokens are semantic, not descriptive. We don't name tokens blue-500. We name them color.primary.500. The primary color might be blue today and teal tomorrow. The token name stays stable. Every component references the semantic name, so a rebrand is a JSON change, not a codebase search-and-replace.
A design token is a decision, not a value. Name the decision, not the color.
§ 03Component architecture that scales
Our component libraries follow a layered architecture. The layers, from bottom to top:
- Primitives.
Box,Text,Stack,Icon. These are unstyled layout components that consume tokens for spacing and typography. They have no visual opinion beyond what the tokens dictate. - Elements.
Button,Input,Badge,Avatar. These compose primitives and add visual styling. Each element has a well-typed props interface with variants (primary,secondary,ghost), sizes (sm,md,lg), and states (disabled,loading). - Patterns.
FormField,DataTable,Modal,CommandPalette. These compose elements into reusable UI patterns that encode interaction behavior, not just visual structure. - Templates. Page-level layouts that compose patterns into complete views. These are product-specific and live in the product repo, not the system package.
Each layer only imports from the layer below it. A pattern never reaches past elements to use a primitive directly. This constraint keeps the dependency graph clean and makes it possible to swap out an element implementation without touching any pattern that uses it.
Each layer only imports from the layer below it. That's the only rule.
— Component architecture principle
§ 04The Figma-to-code pipeline
The gap between Figma and code is where most design systems quietly die. A designer updates a component in Figma, forgets to tell the engineer, and now the system has two sources of truth. Three months later, the Figma file and the code have drifted so far apart that neither one is reliable.
We solve this by making Figma a consumer of the token layer, not a source. Figma Variables (introduced in 2023 and matured significantly since) can be synced from the same token JSON that generates CSS variables. When a token changes in the repository, a GitHub Action pushes the update to Figma via the Figma REST API. The designer sees the change in their next session.
For component structure, we don't attempt full Figma-to-code generation. The tools that promise this — and there are many — produce code that's correct structurally but wrong semantically. They generate divs where you need buttons, pixel values where you need tokens, and inline styles where you need component variants. Instead, we maintain parallel component libraries: one in Figma with auto-layout and variants that mirror the coded API, and one in code that mirrors the Figma structure. The token layer keeps them visually synchronized. The structural parity is maintained through documentation and review.
[ FIG. 002 ] — Token flow from JSON to Figma and code§ 05When to build vs when to adopt
The honest answer: most teams should not build a design system from scratch. If your product has fewer than fifty unique screens and fewer than five engineers, adopting an existing system (Radix, Shadcn, Chakra, Mantine) and customizing it with your tokens will get you 90% of the value at 10% of the cost.
Build your own when:
- Your brand requires it. If your product's visual identity is a competitive advantage — think Stripe, Linear, Vercel — the off-the-shelf system will never feel right. The details that make those products feel distinctive live in the component layer, not the token layer.
- You have platform-specific needs. If you're shipping to web, iOS, and Android from a shared design language, you need a token layer that generates platform-specific outputs. No off-the-shelf system does this well.
- You've outgrown adoption. If you've been customizing Radix for two years and 40% of the components are custom overrides, you've already built a system — you just built it badly. Time to formalize it.
Adopt when:
- You're a small team shipping to one platform.
- Your brand is not visually distinctive (most B2B SaaS falls here).
- You need to ship in weeks, not months.
§ 06The minimum viable system
If you're starting from zero, here's the smallest useful system we've shipped:
# Minimum viable design system 1. Token JSON file with color, spacing, typography, radii 2. CSS custom properties generated from tokens 3. Figma variables synced from the same JSON 4. Five primitives: Box, Text, Stack, Icon, Divider 5. Ten elements: Button, Input, Select, Checkbox, Badge, Avatar, Card, Modal, Toast, Tooltip 6. One documentation page per component with props table 7. A Storybook instance deployed on every PR
This takes about two weeks for a senior engineer to build. It covers 80% of the UI surfaces in a typical product. Everything else gets built as needed, following the same patterns. The key is starting with tokens and primitives, not with the fanciest pattern. If the foundation is right, every component added later will be consistent by default.
The systems that fail are the ones that try to be complete before they're useful. Ship the minimum, use it in production, and let the product's actual needs drive what gets added next. A design system is a product. Treat it like one.
— End of essay. Need a design system that lasts? Start a project →