Jun 4, 2026

Updated Sep 28, 2026

10 min read

AI-Ready Design Systems (5/7)

Component specifications AI tools can implement without guessing

Francois Brill

Francois Brill

Designer + Builder

Component specifications AI tools can implement without guessing

A human style guide describes how a component should look. A component spec for AI is the contract a fresh coding session reads before it touches the file. Props, states, accessibility, and the documented do/don'ts. That's enough to decide whether to use the component, pass the right props, avoid mistakes already on record, and write copy in that component's voice, without re-reading the implementation.

This is Article 5 of AI-Ready Design Systems. Article 1 is why a stateless session needs that contract at all. Article 2 is where specs sit in the folder. Article 4 wires the tokens each spec lists. DESIGN.md holds brand essence and the full palette, not the component contract. AI UI brand governance is how you point agents at those files on every session.

A good spec lets a fresh Claude session do four things without re-reading the implementation:

  1. Decide whether to use this component vs an alternative.
  2. Pass the right props.
  3. Avoid the documented mistakes.
  4. Write copy that fits the voice.

That's the bar. Every section we write in a spec exists to serve one of those four outcomes. If a section doesn't serve any of them, it doesn't belong in the spec.

We learned this the hard way. The first specs we wrote across multiple projects were dense, thorough, and nearly useless. They described components the way a museum placard describes an artifact: historically accurate, contextually stripped. After testing them with Claude on a production Nuxt + Tailwind site, we rewrote the format around that four-things bar. This article walks through what we landed on.

“
A spec is a contract, not a description.

The frontmatter

Every spec file opens with a YAML block. It's the index entry. It tells any reader, human or AI, what kind of thing they're looking at before they read a single paragraph.

---
name: hero-split
tier: organism
type: screen-archetype
status: documented
component: app/components/organisms/HeroSplit.vue
---

Field by field:

  • name: kebab-case, matches the filename. This is the canonical identifier used in [[wiki-links]] throughout the system.
  • tier: foundation, token, atom, molecule, or organism. The tier drives discovery because specs live in matching subdirectories: app/design-system/specs/organisms/ holds organisms, app/design-system/specs/atoms/ holds atoms.
  • type (optional): a sub-taxonomy when tier alone isn't enough. Values we use: row-section, screen-archetype, app-shell-piece. Useful for surfacing related components during discovery.
  • status: covered in its own section below. Get this right.
  • component: the path to the existing file, if one exists. This is the contract pointer. The spec describes the interface; the file is the implementation.

The nine canonical sections

Every spec follows the same nine sections, in this order.

Purpose

One sentence. What is this component for, and why does it exist.

Example:

## Purpose
A two-column hero with an image on the right, used for top-of-page
intros on feature and landing pages.

This section serves outcome one: decide whether to use this component vs an alternative. If an AI is choosing between hero-split and hero-centered, the purpose line makes the decision obvious. Generic purpose lines like "A flexible hero component" don't help. They just consume tokens.

Anatomy

A bullet list of visible parts, outer to inner. Each bullet names the part and its canonical class or token.

Example:

## Anatomy
- Wrapper: `section.relative.bg-white` with `overflow-hidden`
- Grid: `grid lg:grid-cols-2 gap-12 items-center`
- Copy block: left column, `max-w-lg`
  - Eyebrow: `text-sm font-semibold tracking-wide text-brand-600`
  - Heading: `text-4xl font-bold text-gray-900`
  - Body: `text-lg text-gray-600`
- Image block: right column, `aspect-video rounded-2xl overflow-hidden`

We tried writing anatomy in prose paragraphs on one project. Claude parsed it poorly, missed token references, and generated markup that ignored the grid structure entirely. Bullets are faster and more reliable. We reverted and stayed reverted.

Props

A markdown table: Name / Type / Default / Description. Use TypeScript-style union types.

Example:

## Props
| Name     | Type                                              | Default   | Description                          |
|----------|---------------------------------------------------|-----------|--------------------------------------|
| color    | `blue`, `purple`, `red`, `gray`                   | `blue`    | Theme for gradient, eyebrow, icons.  |
| eyebrow  | `string`                                          | `''`      | Small label above the heading.       |
| heading  | `string`                                          | required  | Main headline.                       |
| imageUrl | `string`                                          | required  | Path to the right-column image.      |

This section serves outcome two: pass the right props. The types column earns its width. Union types tell AI exactly which values are blessed. string alone invites hallucinated values.

Usage

One code block, most common use, in the framework's actual syntax.

Example:

<HeroSplit
  color="blue"
  eyebrow="Introducing"
  heading="Design systems that ship"
  imageUrl="/images/hero-product.jpg"
/>

Outcome two again, with outcome three baked in: AI mimics this pattern when generating code. Show an antipattern in the usage example, and AI reproduces it everywhere.

Variants observed in the site

A table listing real variations, their distinguishing props, and where they appear.

Example:

## Variants observed in the site
| Variant    | Props                     | Where used              |
|------------|---------------------------|-------------------------|
| Blue hero  | `color="blue"`            | Homepage, pricing page  |
| Gray hero  | `color="gray"`            | About, contact          |
| No eyebrow | `eyebrow=""` or omitted   | Campaign landing pages  |

This section answers the question AI otherwise guesses at: which variants are actually used, and which are technically possible but wrong for this site. These are the blessed variants. The rest are invitations to drift.

Tokens used

A list of CSS variables and Tailwind utilities the component consumes.

Example:

## Tokens used
- `--color-brand-600` (eyebrow text)
- `--color-gray-900` (heading)
- `bg-gradient-to-br` from `from-brand-50 to-white`
- `rounded-2xl`, `shadow-lg` (image block)

This section exists so AI understands the dependency surface before modifying anything. It doesn't need to open the file to know which tokens are in play.

Voice

How copy inside this component should read. Specific to this component, not the general brand.

Example:

## Voice
- Heading: sentence case, period optional, under 10 words preferred.
- Eyebrow: title case, no punctuation, two or three words.
- Body: one to two sentences, plain language, no jargon, period at end.
- No exclamation marks anywhere in this component.

Outcome four. This section is the most commonly skipped and the most consequential skip. AI defaults to its own copy conventions. Without a voice section, you get "Discover the future of X" in every headline.

Don't

Three to five imperatives. Common mistakes. State them bluntly.

Example:

## Don't
- Don't change the 4-cell icon count without a refactor. The grid is hardcoded `lg:grid-cols-4`.
- Don't override the `-mt-4` on the top wrapper. It's intentional. It bridges to the preceding section.
- Don't use this component at the top of a page. It assumes a hero or split section came before it.
- Don't add a sixth color theme without updating the `color` prop union type and the token map.

We skipped this section on early versions of the format. Felt negative. Felt like distrust. Then Claude rebuilt a container on a sister project with a 5-column icon grid because nothing told it the 4-column structure was load-bearing. We added "Don't" back and never removed it again.

Related

Wiki-style links using [[spec-name]] syntax.

Example:

## Related
- [[hero-centered]] – use when no image is needed
- [[section-row-icons]] – the icon grid that often follows this component
- [[page-shell-marketing]] – the shell this component lives inside

This is how AI traverses the spec graph without loading every spec at once. Each [[link]] is an on-demand pointer. A fresh session can follow the chain as far as the task requires.

Status values

The status field in the frontmatter is not decoration. It changes what AI does with the spec.

  • documented: the spec describes an existing file. The file at component: is the implementation. AI should import it, not rewrite it.
  • pattern: the recipe appears inline in multiple places but has no canonical file. AI should write it inline using the spec as the recipe.
  • proposed: recommended but not built. If AI is building a new page, it can follow this spec as the intended contract. Building the file is a separate, future task.
  • new: created alongside the spec during the current scaffold pass. Spec and file were written together.

Our first pass at status had two values: done and todo. Claude kept trying to import files that didn't exist. todo didn't tell it whether a file might exist somewhere and just needed finding. The four-value system resolves the ambiguity cleanly. documented means "import this." pattern means "use this recipe inline." proposed means "if building, follow this contract." new means "added with the design system."

Good spec vs vague spec

This is the article's center of gravity. Here's the same component spec written two ways.

Vague (don't write this):

## Purpose
A flexible grid component for displaying content.
 
## Props
| items | array | required | The items to display |
 
## Don't
- Don't misuse this component.

Specific (write this):

## Purpose
A bordered, rounded container with a header block on top and a 4-column
icon grid below. The canonical row for "Built for X, Y, Z, and A" content.
 
## Props
| color | `'blue' \| 'green' \| 'purple' \| 'red' \| 'gray' \| 'yellow'` | `'blue'` | Color theme for gradient, eyebrow, icon pads, and accent text. |
 
## Don't
- Don't change the 4-cell count without a refactor.
  The grid is hardcoded `lg:grid-cols-4`.
- Don't override the `-mt-4`. It's intentional. It bridges to the
  preceding section.
- Don't use this standalone at the top of a page. It assumes a hero
  or split came before it.

The specific version is about twice as long. It's infinitely more useful to a fresh session. The vague version occupies context without earning it. It tells AI: "a grid exists." The specific version tells AI: "here's the exact grid, here's what it's for, here's what you cannot change." Those are different things entirely.

Vague specs are a kind of empty politeness. They avoid the work of articulating constraints because articulating constraints feels prescriptive. But prescription is the point. A spec that doesn't prescribe is a placeholder with delusions of documentation.

“

Vague specs take up the context window without earning their place.

Length and depth calibration

Target: 2 to 5 KB per spec file.

We built 8 KB specs on a recent client project. Felt thorough. Tested them with Claude. The long specs made the AI worse. Too much context, conflicting signals, decision paralysis. Trimmed to 2 to 4 KB. Better immediately.

The calibration rule we use now:

  • Atoms and molecules backed by an existing file: 1.5 to 2 KB. The file is the implementation; the spec covers the interface and the constraints.
  • Organisms with multiple variants: 3 to 5 KB. More decisions to capture.
  • Anything creeping past 5 KB: the component is probably doing too much. Consider splitting before writing more spec.
“
2 to 5 KB. Less is vague. More is unread.

What not to put in a spec

Discipline matters here as much as completeness.

  • The implementation source code. Point at the file with component:. Don't paste the <template> block. The spec is the contract; the file is the implementation. They're separate artifacts for a reason.
  • Inline TypeScript types. Those live in the component file. The props table is descriptive, not authoritative. If they diverge, the file wins.
  • Brand essence and philosophy. That belongs in DESIGN.md under the Overview section.
  • The full color palette. Also DESIGN.md. The spec lists only the tokens this component actually uses.
  • Marketing copy. Even when a component is for marketing, the spec describes the contract. It doesn't write the message.

The rule is simple. If something belongs in a shared reference file, it belongs there. The spec points at those files when needed. It doesn't absorb them.

“
Documentation, not regeneration.

States and accessibility (only when the component is interactive)

Decorative and layout organisms can skip this. Buttons, inputs, menus, and anything with loading or error cannot. List the states a session will otherwise omit. One line each: what changes, and the constraint.

  • Default: base styling. No token override.
  • Focus-visible: outline or highlight. Layout stays stable.
  • Disabled: label and layout stay. Use the contrast tokens in Article 4.
  • Loading: spinner. Label persists. Layout stable.
  • Error: tinted border. Label stays. Name the error token.
  • Empty: placeholder copy. Same width as filled.

Accessibility is a constraint, not an audit: role, accessible name, and keyboard behavior if they are not obvious from the file. When the spec says one thing and the code does another, the session copies the file. Not an axe walkthrough, ARIA encyclopedia, slot essay, or JSON Schema.

The four things, restated

Every section of a well-written spec earns its place by serving one of the original four outcomes.

Purpose and Related help AI decide whether to use this component. Props, Anatomy, Variants, and Usage help AI use it correctly. Don't and Tokens help AI avoid the documented mistakes. Voice helps AI write copy that fits.

This is what we ship in app/design-system/specs/ on every project now. The format took several projects to stabilize. Each project contributed a failure the format wasn't yet equipped to prevent. That's the actual origin of each section. Not design intuition. Observed mistakes, captured as constraints, tested with real sessions until they stopped happening.

A good spec gives a fresh session exactly what it needs and nothing it doesn't. That's the standard. Every section, every field, every Don't entry either earns its place against one of those four outcomes, or it gets cut. If the inventory isn't mapped yet, audit before you scaffold. The Claude Code skill in Article 7 is how we run this on a repo.

This is Article 5 of AI-Ready Design Systems.

Frequently asked questions

What is a component spec for AI?
A component spec for AI is the contract a coding session reads to work with a component correctly. It's not a style guide. A style guide tells you how something should look. A component specification tells you what props exist, what states matter, what accessibility requirements apply, and what mistakes have already been documented. A fresh session can open it and get to work without re-reading the implementation file.
What must every component specification include?
Every component specification opens with YAML frontmatter: name, tier, status, and the component field pointing at the implementation file. Then nine sections in order: Purpose, Anatomy, Props, Usage, Variants observed in the site, Tokens used, Voice, Don't, and Related. Interactive components add a short states-and-accessibility note after those nine. That note is not a tenth section. Target 2 to 5 KB. Point at the file. Don't paste the source into the spec.
How do component specs prevent AI drift?
They name what's blessed. A spec lists the variants a session is allowed to use, the tokens the component consumes, and mistakes a previous session already made. The Don't section needs a reason, not just a rule. Don't change the 4-cell icon count without a refactor, because the grid is hardcoded lg:grid-cols-4. That gets followed. A bare "don't misuse this" gets ignored. Status tells the session what to do next. Documented means import the existing file. Pattern means write the recipe inline. Proposed means follow the contract when building. New means the file was scaffolded with the spec.
Where do component specs live relative to tokens and DESIGN.md?
One file per component, in app/design-system/specs/, beside the implementation the frontmatter points at. Specs list the tokens each component consumes at runtime. Article 4 is where those tokens get wired. DESIGN.md holds brand essence and the full palette, not the component contract. Article 1 is why a stateless session needs that split. Article 2 is where the spec files sit in the folder. The series hub is the map. AI UI brand governance is how you point agents at those files once they exist.

About the author

Francois Brill

Designer + Builder, Clearly Design, Inc.

Francois has been designing and shipping software products since 2002, with a focus on the messy middle between design and the codebases that consume them. He runs Clearly Design, a product design subscription studio for SaaS founders, and writes about how design systems hold up under AI-assisted development.

X / TwitterClearly DesignGitHubLinkedIn

Want specs your AI sessions can actually build from?

Clearly Design writes the source-of-truth specs that let AI tools use your components correctly and in the right voice, every session. Part of a product design subscription.