Skip to content
BlackFig

Building a design system for your MVP

AntPublished 6 min read

Quick answer

An MVP design system is small: a set of tokens for type, colour, spacing and radius, a dozen components that use only those tokens, and one page of rules for layout and states. In a Tailwind v4 and shadcn/ui app it lives in globals.css and components/ui, and takes days to set up, not months.

On this page
  1. What a design system means at MVP stage
  2. Why AI-built apps need one more than most
  3. Real examples of the three layers
  4. How big should it be
  5. Where to start this week
  6. When to get help

What a design system means at MVP stage

The phrase makes people think of Material Design or Polaris: hundreds of components, a documentation site, a team. That is a design system for a company with dozens of product teams. An MVP needs something much smaller, with the same purpose: every new screen should look like it belongs to the same product without anyone having to think hard about it.

At MVP stage that comes down to three layers.

  1. Tokens. Named values for the decisions you make once: typefaces, a type scale, colour roles, a spacing step, corner radius, shadows. Everything else refers to these names, never to raw values.
  2. Components. The dozen or so building blocks your screens actually use: button, input, select, card, table, dialog, toast, badge, tabs, empty state. Each one uses only tokens.
  3. Rules. One page of decisions that tokens and components cannot hold on their own. Where the primary action goes. How forms show errors. What every list does when it is empty. How dense the tables are.

That is it. No documentation site, no versioned package, no governance process. You can add those when there is a team to govern.

Why AI-built apps need one more than most

An AI builder starts every generation with no memory of the taste behind the last one, unless you give it something to hold on to. Ask for a settings page on Monday and a billing page on Thursday and you may get two slightly different shades of grey, two button heights and two ways of showing errors. Each looks fine alone. Together they make the product feel assembled rather than designed.

A small design system is that something to hold on to. The tools are built to use one:

  • v0's Design Systems 2.0 lets you point v0 at your system's sources, such as a repository, an app that uses it, docs and Figma frames. It builds a starter app to check it understands the system, then saves it as a skill that later chats draw on.
  • Lovable can connect projects to a shared design system on paid plans, so they share the same components and styles. On any plan you can save fonts, colours and style keywords to a project's instructions.

Both work far better when the system is small and consistent. A theme file and a component folder that follow clear rules are easy for a model to pick up. A sprawl of one-off classes is not.

Real examples of the three layers

Here is what each layer looks like in a Next.js app with Tailwind v4 and shadcn/ui.

Tokens in globals.css

shadcn/ui already gives you a token structure: semantic pairs like primary and primary-foreground, muted and muted-foreground, plus border, input, ring and a --radius that the whole radius scale derives from. Your job is to set the values on purpose and add only what is missing.

Tailwind v4's @theme directive turns variables into utilities. Its docs list the namespaces: --color-* for colours, --font-* for families, --text-* for sizes, --radius-*, --shadow-* and a single --spacing value that drives padding, margin and sizing utilities.

/* app/globals.css: additions on top of the shadcn/ui theme */
@theme {
  /* Type scale: five sizes is enough for most MVPs */
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.25rem;
  --text-display: 2rem;
  --text-display--line-height: 1.15;
 
  /* Two shadows: one for raised surfaces, one for overlays */
  --shadow-*: initial;
  --shadow-raised: 0 1px 2px oklch(0 0 0 / 0.06);
  --shadow-overlay: 0 8px 24px oklch(0 0 0 / 0.12);
}
 
:root {
  --radius: 0.5rem;
  /* Status colours the default theme does not include */
  --success: oklch(0.52 0.12 150);
  --success-foreground: oklch(0.985 0 0);
  --warning: oklch(0.84 0.16 84);
  --warning-foreground: oklch(0.28 0.07 46);
}
 
@theme inline {
  --color-success: var(--success);
  --color-success-foreground: var(--success-foreground);
  --color-warning: var(--warning);
  --color-warning-foreground: var(--warning-foreground);
}

The --shadow-*: initial line uses Tailwind's namespace reset: it removes the default shadow-sm, shadow-md and the rest, so only your two shadows exist. That is the point of a system. If a shadow is not in the list, nobody can use it by accident, including an AI tool. You can do the same for colours with --color-*: initial, though with shadcn/ui it is simpler to keep the semantic tokens and simply never use the raw palette in app code. (If you reset shadows, check any shadcn/ui components that use shadow-xs or shadow-sm and swap in your own names.)

The warning values above come straight from the shadcn/ui docs' example for adding a token. Remember to add .dark values for each new token too.

Components in components/ui

shadcn/ui copies component source into your project, so the component layer is already there. Treat that folder as the system:

  • Edit the files to match your tokens and density, rather than overriding them on every screen.
  • Add variants with cva when you need a new style, for example a subtle button.
  • Add the components shadcn/ui does not have but your product needs everywhere: a page header, a stat with a label and change indicator, a money cell that formats pounds and pence.
  • Delete what you do not use. A smaller folder is easier for people and models to follow.

Rules in one page

Write them in the repository, in a file like DESIGN.md, and paste the same text into your AI tool's project instructions. Keep it short enough that someone will actually read it.

# Design rules
 
- One primary button per screen, top right of the page header.
- Use semantic tokens only (bg-primary, text-muted-foreground). Never raw palette classes.
- Body text is text-sm. Page titles use font-display text-display.
- Tables: 40px rows, numbers right-aligned with tabular-nums, money formatted en-GB GBP.
- Every list and table has an empty state with a heading, one sentence and one action.
- Errors sit under the field, in text, with a fix. Never colour alone.
- Loading: skeletons for full pages, spinners inside a single panel.

How big should it be

This is the question that matters most, because an MVP design system can fail by being too big as easily as too small.

LayerMVP versionAdd when
TypefacesOne family, maybe a second for headingsA distinct brand voice needs it
Type scaleFour or five sizesContent gets long-form, like docs or articles
ColourNeutrals, one accent, status coloursA second product area needs its own identity
SpacingTailwind's default step, used consistentlyDensity needs to differ between areas
Radius and shadowOne radius, two shadowsRarely
Components10 to 15, all in useThe same pattern is built by hand a third time
RulesOne pageA second designer or team joins
DocumentationThe rules page and the codeOther teams need to use it without asking you
Token exchange formatNot neededTokens must sync between Figma and several codebases

The last row is worth a note. The W3C Design Tokens Community Group published the first stable version of its format specification, version 2025.10, for moving tokens between design tools and code. If you have one Figma file and one codebase, you do not need it yet. If you are about to run several products off one brand, it is worth reading before you invent your own format.

Where to start this week

If your app already exists and was built with an AI tool, you do not need to stop and redesign it. Do this in order:

  1. Audit what exists. Search the codebase for raw colour classes, one-off font sizes and custom shadows. The list tells you which decisions were never made.
  2. Set the tokens. Typeface, accent, neutrals, radius. The code for this is in how to make a shadcn app not look like shadcn.
  3. Replace raw values with tokens, screen by screen. This is tedious and very effective. Most of the visual inconsistency goes away here.
  4. Write the rules page, and paste it into your AI tool's instructions.
  5. Fix the components last, once you can see which ones are used and how.

Once that is done, new screens start to look like the old ones, which is the whole point. For where this fits with type, colour, layout and states, the design guide for AI-built apps has the full picture, and why every AI-built app looks the same explains what you are working against.

When to get help

Setting up tokens is mechanical. Deciding what they should be, and which rules your product needs, is design work: it depends on who uses the product and what they do with it. I set up small systems like this as part of every build, in Figma and in code, because I do both. You can see one in practice on FindPopups, or read what a designer who codes actually does.

Sources

Questions founders ask

Does an MVP need a design system?

It needs a small one. Without agreed tokens and components, every new screen gets its own colours and spacing, and AI tools make that worse because each generation starts fresh.

Should I design the system in Figma first?

If you design in Figma, yes, set up the same tokens there so design and code match. If you design in code, the theme file and component folder are the system, and Figma can come later.

What is the difference between a design system and a UI kit?

A UI kit is a set of components. A design system adds the decisions behind them: which tokens exist, when to use each component, and how screens are laid out. For an MVP the decisions matter more than the component count.

Ant

Product designer who builds MVPs, based in Nottingham. 10+ years designing digital products, and the only person at BlackFig. More about me