Every design system is built on a layer of decisions that most people never see. Before you create your first button or card component, you need color scales, type ramps, spacing units, elevation tokens, and motion curves. These are your foundations — the raw materials that every component draws from. Get them right and your system scales cleanly. Get them wrong and you'll spend months patching inconsistencies that compound with every new screen.
This guide walks through each foundation category, explains why it matters, shows how it's structured as design tokens, and demonstrates the three-tier architecture that connects raw values to real components. If you're building a design system for the first time — or inheriting one that feels chaotic — this is where to start.
What “Foundations” Means in a Design System
Components get all the attention. Buttons, modals, data tables — these are the things designers and developers interact with daily. But components are assembled from something. That something is foundations.
Foundations are the design decisions that exist below the component layer: color palettes, type scales, spacing units, elevation levels, border radii, and motion curves. They're the physics of your UI. Just as physical materials have properties — density, elasticity, conductivity — your design system's foundations define the properties that every component inherits.
Why bother formalizing them? Three reasons:
- Consistency — When every component pulls from the same spacing scale, visual rhythm happens automatically. You stop arguing about whether this card should have 12px or 16px of padding because the scale makes the answer obvious.
- Scalability — A team of three can hold spacing values in their heads. A team of thirty cannot. Foundations encoded as tokens become a shared source of truth that scales with your organization.
- Theme support — Dark mode, multi-brand products, high-contrast accessibility modes — all of these become manageable when your foundations use a layered token architecture instead of hardcoded values.
The Three-Tier Token Architecture
The most effective design systems organize their tokens into three layers:
- Reference tokens (also called core or primitive tokens) — Raw values with no opinion about usage.
color.palette.blue.500is a reference token. It says “this is a specific shade of blue” and nothing more. - Semantic tokens — Intent-based aliases that point to reference tokens.
color.background.brandpoints tocolor.palette.blue.500today, but could point to a different value in a dark theme or a different brand. The name describes why you'd use it, not what it looks like. - Component tokens — Highly specific tokens scoped to individual components.
button.background.primarypoints tocolor.background.brand. Components reference these, making it possible to override a single component's appearance without affecting the rest of the system.
This architecture means you can change color.palette.blue.500 in one place and it cascades through semantic and component layers. You can swap an entire theme by redirecting semantic aliases. And you can fine-tune a single component without breaking the chain.
Reference: color.palette.blue.500 = #428DFF
↓
Semantic: color.background.brand = {color.palette.blue.500}
↓
Component: button.background.primary = {color.background.brand}
Keep this mental model as we walk through each foundation. Every category follows this same pattern: raw scale → semantic role → component application.
Color Foundations
Color is usually the first foundation teams tackle, and it's where the three-tier architecture pays off most visibly.
Building a Reference Palette
Start with your brand colors and expand them into a full scale. Most systems use a numbered scale — 100 through 900 — where lower numbers are lighter and higher numbers are darker. This gives you enough range for backgrounds, text, borders, hover states, and accessibility modes.
Beyond brand colors, you need:
- Neutral grays — For text, backgrounds, borders, and dividers. These do the heavy lifting in most interfaces.
- Status colors — Info (blue), success (green), warning (amber), danger (red). Each needs its own scale for backgrounds, text, and borders.
- Data visualization colors — Sequential, categorical, and divergent palettes that remain distinguishable at small sizes and for colorblind users.
In W3C Design Token format, a palette entry looks like this:
{
"color": {
"palette": {
"brand": {
"primary": {
"500": { "$type": "color", "$value": "#428DFF" }
}
}
}
}
}
Semantic Color Tokens
Once your palette exists, create semantic tokens that describe purpose, not appearance. Common semantic color categories:
- Surface / Background —
color.background.primary,color.background.elevated,color.background.brand - Text / Foreground —
color.foreground.primary,color.foreground.secondary,color.foreground.onBrand - Interactive —
color.border.focus,color.border.subtle,color.border.strong - Feedback —
color.status.info,color.status.success,color.status.warning,color.status.danger
Each semantic token aliases a reference token. When you build a dark theme, you swap the aliases — color.background.primary points to gray.800 instead of gray.100 — and every component that uses it updates automatically.
Accessibility: Contrast Ratios
Color accessibility is non-negotiable. At minimum, enforce WCAG 2.x AA contrast ratios: 4.5:1 for normal text, 3:1 for large text. For dark mode, consider APCA (Accessible Perceptual Contrast Algorithm), which handles light-on-dark contrast more accurately than the older WCAG formula.
Build contrast checks into your token pipeline. When a brand pack resolves, automatically verify that every foreground/background pair meets your contrast threshold. Fail the build if they don't. This catches accessibility regressions before they ship.
Typography Foundations
Typography foundations define how text looks and behaves across your entire product. Done well, they create a clear visual hierarchy without any designer needing to manually set font sizes.
Type Scale Selection
Choose a mathematical ratio for your type scale. Common options:
- Major Third (1.25) — Subtle, works well for dense applications
- Perfect Fourth (1.333) — The most common choice, balances hierarchy and density
- Golden Ratio (1.618) — Dramatic, better for editorial or marketing pages
Apply the ratio to a base size (typically 16px for body text) to generate your scale. A Perfect Fourth ratio produces: 12px, 14px, 16px (base), 18px, 20px, 24px, 32px. Encode each step as a token:
{
"typography": {
"size": {
"scale": {
"xs": { "$type": "dimension", "$value": "12px" },
"sm": { "$type": "dimension", "$value": "14px" },
"md": { "$type": "dimension", "$value": "16px" },
"lg": { "$type": "dimension", "$value": "18px" },
"xl": { "$type": "dimension", "$value": "20px" },
"2xl": { "$type": "dimension", "$value": "24px" },
"3xl": { "$type": "dimension", "$value": "32px" }
}
}
}
}
Font Stack Strategy
Define font families as tokens and include robust fallbacks. A modern stack typically includes:
- Sans-serif for UI text —
'Inter', system-ui, -apple-system, Segoe UI, Roboto, sans-serif - Serif for editorial content —
'Newsreader', Georgia, serif - Monospace for code —
'Monaspace', ui-monospace, SFMono-Regular, Menlo, monospace
Variable fonts are increasingly the right default — they reduce HTTP requests and give you fine-grained weight and width control from a single file.
Semantic Type Tokens
Compose atomic tokens (family, weight, size, line-height, letter-spacing) into semantic sets:
{
"typography": {
"heading": {
"1": {
"fontFamily": { "$type": "fontFamily", "$value": "{typography.fontFamily.inter}" },
"fontWeight": { "$type": "fontWeight", "$value": "{typography.fontWeight.bold}" },
"fontSize": { "$type": "dimension", "$value": "{typography.size.scale.3xl}" },
"lineHeight": { "$type": "dimension", "$value": "{typography.lineHeight.tight}" },
"letterSpacing": { "$type": "dimension", "$value": "{typography.letterSpacing.tight}" }
}
},
"body": {
"default": {
"fontFamily": { "$type": "fontFamily", "$value": "{typography.fontFamily.inter}" },
"fontWeight": { "$type": "fontWeight", "$value": "{typography.fontWeight.regular}" },
"fontSize": { "$type": "dimension", "$value": "{typography.size.scale.md}" },
"lineHeight": { "$type": "dimension", "$value": "{typography.lineHeight.normal}" }
}
}
}
}
Readability Guidelines
Good type tokens alone aren't enough — you need guidelines for how they're applied:
- Line height — Body text needs at least 1.5x the font size for comfortable reading. Headings can tighten to 1.2x.
- Letter spacing — Tighten for large headings (
-0.01em), keep neutral for body, widen slightly for small caps or labels (0.02em). - Measure (line length) — Aim for 45–75 characters per line. Longer than that and the eye loses its place on the return sweep.
Spacing & Layout Foundations
Spacing is the connective tissue of your UI. It determines how elements group together, how much breathing room content has, and whether your interface feels cramped or spacious.
Base Unit and Spacing Scale
Most design systems use a 4px base unit. Every spacing value is a multiple of 4: 4, 8, 12, 16, 20, 24, 32, 40, 48. This creates a predictable rhythm that's easy for both designers and developers to internalize.
Some teams use an 8px base for simpler math at the cost of fewer intermediate steps. The 4px base is more flexible — it gives you the 12px and 20px values that 8px systems lack, which matter for compact UI patterns like data tables and toolbars.
{
"spacing": {
"base": { "$type": "dimension", "$value": "4px" },
"scale": {
"1": { "$type": "dimension", "$value": "4px" },
"2": { "$type": "dimension", "$value": "8px" },
"3": { "$type": "dimension", "$value": "12px" },
"4": { "$type": "dimension", "$value": "16px" },
"6": { "$type": "dimension", "$value": "24px" },
"8": { "$type": "dimension", "$value": "32px" },
"12": { "$type": "dimension", "$value": "48px" }
}
}
}
Layout Tokens
Beyond raw spacing, define semantic layout tokens for recurring patterns:
- Container padding —
spacing.padding.container(typically 24px) - Card padding —
spacing.padding.card(typically 16px) - Grid gap —
spacing.gap.grid(typically 16px)
Grid Systems and Breakpoints
Define your breakpoints as tokens so they're referenceable across media queries, JavaScript, and server-side rendering:
{
"dimension": {
"breakpoint": {
"sm": { "$type": "dimension", "$value": "640px" },
"md": { "$type": "dimension", "$value": "768px" },
"lg": { "$type": "dimension", "$value": "1024px" },
"xl": { "$type": "dimension", "$value": "1280px" }
}
}
}
Column count, gutter width, and container max-width should also be tokenized. The specific values depend on your product — a data-heavy enterprise application might use a 12-column grid with 16px gutters, while a marketing site might use a simpler 4-column layout with wider margins.
Elevation & Depth
Elevation creates the illusion of layers in a flat medium. It communicates which elements sit above others and helps users understand what's interactive versus static.
Shadow Scales
Define a progressive shadow scale where higher levels cast larger, softer shadows:
{
"elevation": {
"level": {
"1": {
"$type": "shadow",
"$value": "0px 1px 3px rgba(0,0,0,0.12), 0px 1px 2px rgba(0,0,0,0.08)"
},
"2": {
"$type": "shadow",
"$value": "0px 3px 6px rgba(0,0,0,0.14), 0px 2px 4px rgba(0,0,0,0.10)"
}
}
}
}
Then create semantic aliases that describe surface types rather than numeric levels:
elevation.surface.raised→ level 1 (cards, list items)elevation.surface.floating→ level 2 (dropdowns, popovers, modals)
Border and Divider Tokens
Borders handle what shadows cannot — crisp, precise separation between adjacent elements. Tokenize border width, style, and color independently so they compose cleanly:
- Width —
shape.border.width.hairline(1px),shape.border.width.thick(2px) - Style —
shape.border.style.solid,shape.border.style.dashed - Color — Uses semantic color tokens:
color.border.subtle,color.border.strong,color.border.focus
Z-Index Management
Z-index is the hidden foundation that breaks when it's not managed. Define a z-index scale with named slots:
z.base(0) — Normal document flowz.dropdown(100) — Menus, selectsz.sticky(200) — Sticky headers, toolbarsz.modal(300) — Modals and overlaysz.toast(400) — Notifications and snackbars
Without this, teams inevitably end up with z-index: 99999 wars.
Motion Foundations
Motion makes interfaces feel alive, but uncontrolled motion makes them feel chaotic. Motion foundations give you consistent, purposeful animation across your entire product.
Duration Scale
Define a small set of duration tokens that cover all use cases:
- Instant (100ms) — Micro-interactions: button presses, checkbox toggles, ripple effects
- Short (150ms) — Enter transitions: tooltips appearing, menus opening
- Medium (250ms) — Standard transitions: page sections, panels, accordions
- Long (400ms) — Deliberate transitions: modals, full-page transitions, complex state changes
Resist adding more than four or five durations. If every animation has a unique timing, you don't have a system — you have a collection of one-offs.
Easing Curve Tokens
Easing defines the acceleration profile of an animation. Three to four curves cover nearly all cases:
- Standard —
cubic-bezier(0.4, 0, 0.2, 1)— For most transitions. Elements start fast and decelerate naturally. - Emphasized In —
cubic-bezier(0.2, 0, 0, 1)— For elements entering the viewport. Starts slow, ends decisively. - Emphasized Out —
cubic-bezier(0.4, 0, 1, 1)— For elements leaving. Starts at speed, trails off.
Reduced Motion
Every motion token should have a reduced-motion counterpart. When prefers-reduced-motion: reduce is active, durations should collapse to near-zero and opacity-based transitions should replace movement-based ones. This isn't an edge case — it's a core accessibility requirement. Build it into your token pipeline so it's automatic, not an afterthought.
Putting It Together: A Token File Walkthrough
Let's see how all these foundations connect in practice. A real token system splits into two files that a build tool resolves at compile time.
The W3C Design Token Format
The W3C Design Tokens Community Group specification defines a standard JSON format for tokens. Every token has a $type (what kind of value it is) and a $value (the value itself, or an alias to another token):
{
"color": {
"palette": {
"gray": {
"100": { "$type": "color", "$value": "#F7F8FA" },
"800": { "$type": "color", "$value": "#252A30" }
}
}
},
"spacing": {
"base": { "$type": "dimension", "$value": "4px" }
},
"motion": {
"duration": {
"short": { "$type": "duration", "$value": "150ms" }
},
"easing": {
"standard": {
"$type": "cubicBezier",
"$value": "cubic-bezier(0.4, 0, 0.2, 1)"
}
}
}
}
Aliases use curly-brace references: {color.palette.gray.100}. The build tool resolves these recursively — a semantic token can alias a reference token, and a component token can alias a semantic token.
Style Dictionary Configuration
Style Dictionary (v4) is the most widely used tool for processing design tokens. It reads your token JSON, resolves aliases, and outputs platform-specific formats:
- CSS custom properties —
--color-background-primary: #F7F8FA; - TypeScript exports — Type-safe token objects for React components
- iOS Swift constants —
UIColordefinitions - Android XML — Resource values
The key insight: your source of truth is the token JSON. Everything else is a build artifact. Designers update tokens in one place (often via Tokens Studio for Figma), and the pipeline distributes changes to every platform automatically.
Connecting Tokens to Components
Components should never reference raw values. A button doesn't use #428DFF — it uses button.background.primary, which resolves through the semantic layer to the reference layer. This indirection is what makes theming, dark mode, and multi-brand support possible without rewriting component code.
// A component style function consuming tokens
function buttonStyles(tokens, variant) {
return {
background: tokens.color.background.brand,
color: tokens.color.foreground.onBrand,
borderRadius: tokens.shape.control.radius.default,
height: tokens.dimension.buttonMinHeight,
padding: `${tokens.spacing.scale[2]} ${tokens.spacing.scale[4]}`,
boxShadow: tokens.elevation.surface.raised,
transition: `all ${tokens.motion.interaction.enter.duration}
${tokens.motion.interaction.enter.easing}`
};
}
Notice how every property comes from a token. The component has zero hardcoded values. Swap the token set and you get a completely different visual expression from the same component code.
Validating Your Foundations
A mature token pipeline includes automated checks at build time:
- Alias coverage — Every required semantic key must resolve to a concrete value. Missing aliases break the build.
- Contrast checks — Foreground/background token pairs must meet WCAG AA contrast ratios.
- Size invariants — Tap targets must be at least 44px. Body text must be at least 16px with at least 1.5x line height.
- Motion safety — Reduced-motion variants must exist for every duration token.
These checks turn your design system from a set of guidelines into an enforceable contract. When a new theme or brand pack is created, the build proves it meets accessibility and usability standards before any code ships.
From Foundations to Components
Foundations aren't isolated styles — they compose to create components. A single button uses tokens from five or six foundation categories: color for its background and text, typography for its label, spacing for its padding, shape for its border radius, elevation for its shadow, and motion for its hover transition.
The better your foundations, the more cohesive your components will be — not because you enforced consistency manually, but because the system makes inconsistency difficult. That's the real power of a well-built foundation layer: it turns good defaults into the path of least resistance.
If you're just starting out, begin with color and typography — they're the most visible and will give you the fastest sense of a unified system. Add spacing next, then elevation and motion. Build your token JSON from day one, even if it starts small. The three-tier architecture (reference → semantic → component) scales from a five-token starter kit to a multi-brand enterprise system without architectural changes.
The foundations you set today become the physics of every interface your team builds tomorrow.