Image of Design System

Design System

2026/08/01
ARTICLE

Why Bother With Design Systems

A lot of my older projects faced the same problem: inconsistency.
A button gets rebuilt slightly differently each time, a color gets picked just because it looks OK, or a font size gets smaller because the text doesn’t fit.
These small inconsistencies add up fast and soon nothing feels right.

This is called design debt.
You don’t need a whole team to create it, but working alone is enough.

A design system is the fix.
It is a set of design decisions made once instead of remade again and again, so you can build a product consistently and efficiently at scale.

Typography

Before touching a project, know your three font categories.

  • Serif: small decorative strokes at the end of each letter. They look classic, formal, and traditional.
  • Sans-serif: No serifs, clean edges. Feels modern, minimal, easy to read at small sizes.
  • Monospace: Every character takes the same horizontal width. Built for code editors, terminals, and anywhere alignment matters character-by-character.

Most projects only need one or two of these. Pick based on what the product needs to communicate, not what looks trendy.

Pairing Fonts

A common approach is one font for headings, one for body — usually sans-serif + serif, or two weights from the same family.

Font settings

Once you've picked your families, four settings do the rest of the work:

  • Weight: How thick or heavy the font is
  • Size: Should follow a scale, not random values
  • Leading: Vertical space between lines
  • Tracking: Horizontal space between letters

Color

Same idea as typography. Don't just pick colors that look nice. Decide what each color's job is.

Color Roles

  • Primary: The color most associated with your identity. Used sparingly, mostly for key actions and highlights.
  • Secondary: Supports the primary color, used to draw attention to specific elements (a button, a highlighted state).
  • Neutral: Your grays, blacks, whites. Does most of the actual work — backgrounds, text, borders, dividers.
  • Feedback / Status: Colors with a fixed meaning: success (green), warning (amber), error (red), info (blue).

Semantic Colors

Semantic colors add context and meaning to the global color palette by grouping them into UI-specific roles.

  • Background: For elements such as page backgrounds.
  • Foreground: For elements such as button backgrounds.
  • Text: For text styles.
  • Border / Stroke: For coloring borders.
  • Icon: For iconography.

Accessibility

Color choices aren't just visual — they have to be readable for everyone, including people with low vision or color blindness.

  • Contrast Ratios: Text against background needs enough contrast to meet the Web Content Accessibility Guidelines (WCAG).
  • No Color Alone: Avoid relying on color by itself to show errors, active states, or links. Add extra cues like text labels, icons, or underlines.
  • Testing Tools: Test your system using color blindness simulators and contrast checkers in tools like Figma or WebAIM to catch errors early.

Spacing & Sizing

Consistent and intentional use of space creates better user experience.
A spacing system is also useful for responsive design, which enhances accessibility and quality of the product.

Base Unit

Most systems build off a single base unit, usually 4px or 8px. Every spacing value in the project is a multiple of that number.
Atlassian, for example, builds their whole spacing system around an 8px base unit, scaling from 0px up to 80px.

The Scale

Instead of picking any number that "feels right," restrict yourself to a fixed set of steps, something like 0, 4, 8, 12, 16, 24, 32.
A limited scale forces consistency and speeds up decisions: you're choosing from a short list, not inventing a new number every time.

Rough Grouping By Size

  • Small (0–8px): gaps between icons and text, padding inside compact components, spacing inside a card.
  • Medium (12–24px): container padding for buttons, spacing between elements within a card.
  • Large (32–80px): spacing between major sections of a page, top-level layout gaps.

Design Principles

Tokens (typography, color, spacing) are the building blocks.
Principles are how you actually use them together to build a good interface.

Hierarchy

Use scale — size, weight, color, spacing — to rank what matters most. Not everything on a screen deserves equal attention.
To be more specific, pick 3~5 font sizes for the whole project, and make the steps between them big.
Small jumps in size don't read as hierarchy — they just look like a mistake.

Contrast

Different job than accessibility contrast (covered in Color).
This is about emphasis. Using contrast on purpose to pull the eye toward what matters.
A destructive action like "Delete Account" in red against a muted "Cancel" button is a clear example.
Contrast tells the user which one to think twice about.

Proximity & Grouping

Things that belong together should look like they belong together.

  • Similarity: Items with a shared purpose should share a visual style (a list, a table, a set of cards).
  • Proximity: Related elements sit close together, and unrelated ones get space between them.

Put play, pause, and rewind next to each other because they're all playback controls.
Don't put "quit" in that same cluster because it doesn't belong to the same action group.

Alignment

Left align is the default for a reason. It's the easiest to read, since every line starts in the same place.
Center and right align can look intentional in small segments (a heading, a pull quote) but get harder to read the longer the text runs.

Consistency

A button that looks or behaves differently for no reason creates confusion. That hesitation is friction you didn't need to add.
This is the whole point of a design system. Reuse the same patterns everywhere, and only break from them when you have an actual reason to.

CSS & Tailwind

Tokens don't mean anything until they're wired into actual code.
This is where typography, color, and spacing scales become variables, and where Tailwind either helps you or gets in the way, depending on how you use it.

CSS Variables

Define every token once, in one place, as CSS custom properties:

:root {
  --color-primary: #1b9af5;
  --color-bg: #ffffff;
  --color-text: #1f2937;

  --space-100: 8px;
  --space-200: 16px;

  --font-size-lg: 1.25rem;
}

.dark {
  --color-bg: #030712;
  --color-text: #f9fafb;
}

This decouples your actual values from whatever framework sits on top.
Dark mode, theme switching, all handled by swapping variable values in one file, not hunting through every component.

Where Tailwind Falls Short

Tailwind CSS could be painful for developing a design system.

  • Hard to refactor. A div with 15 chained class names doesn't tell you what the UI actually looks like. You have to mentally build the picture yourself, every time.
  • It leaks. Letting outside code just "add a className" to your component means anyone can override anything, anytime. There's no real boundary, which defeats the purpose of having a component at all.

Using Tailwind Properly

The fix isn't avoiding Tailwind — it's not letting utility classes be the design system.
Wrap them inside a small set of real components instead (e.g. a Button, a Card, an Input).
Each one has a fixed set of allowed variants (primary, secondary, danger — not any string you can type).
Utility classes still do all the actual styling work underneath.
The difference is they're contained inside one component, wired to your actual color and spacing tokens, instead of duplicated across every file that needs a button.

Motion

Motion is a token too. Duration, easing, and distance are decisions, not vibes.

Duration

Interface animations should be fast enough to not feel like waiting, slow enough to actually notice.
The sweet spot for most UI motion is roughly 200–500ms.
Anything under 100ms is invisible; anything over a second starts to feel like lag.
Decorative or hero animations (the kind I use in GSAP, WebGL work) are the exception — those can run longer since the goal is presence, not speed.

Easing

Don’t use linear motion. Nothing in the physical world starts and stops instantly.
Ease-in-out is the safe default for most interface transitions, ease-out (fast start, slow settle) works well for elements appearing on screen.

Purpose Over Decoration

Motion should tell the user something — that two elements are related, that one thing caused another, where they are in a flow.
If an animation doesn't support one of those, it's decoration, and decoration should be used sparingly and intentionally, not by default.

Useful Resources

Here are some design systems worth checking: