AI-Native DesignCase Studies

Building a Design System Documentation Site

Architecture, component docs, and live preview patterns.

The Prompt Engineering Project February 19, 2025 10 min read

Quick Answer

Design system docs should include live component previews, prop/API tables, usage guidelines with do/don't examples, copy-paste code snippets, and accessibility notes for every component. Structure documentation by component with consistent sections. The best design system docs are interactive, searchable, and maintained alongside the code. They reduce support questions and drive adoption by making the right choice the easy choice.

A design system without documentation is a design system that does not get adopted. This is not a theory. It is a pattern we have observed repeatedly: teams build component libraries, define token systems, establish principles -- and then nobody uses them because nobody can find them, understand them, or trust that they are current. Documentation is not the afterthought that follows the design system. Documentation is the product that makes the design system usable.

The Prompt Engineering Project built a full documentation site for its design system at the /design route. This article covers the architecture decisions, the component library we built for the documentation itself, the technical implementation, and the lessons we learned treating documentation as a first-class product.

The Problem: Design Systems That Nobody Uses

The failure mode is predictable. A team invests weeks building a design system. They create tokens for colors, spacing, and typography. They build a component library with buttons, inputs, cards, and modals. They document everything in a Notion page or a Storybook instance. Six months later, half the team is using the components, the other half is writing custom CSS, and the tokens have drifted from the implementation because nobody updated the documentation when the values changed.

The root cause is a documentation architecture problem. Notion pages go stale because they are decoupled from the codebase. Storybook instances break because they require parallel maintenance. README files in component directories are invisible to everyone except the developers who happen to be working in that directory. None of these approaches treat documentation as a living product that evolves with the system it describes.

The design system is not the tokens, the components, or the principles. The design system is the documentation that makes those things discoverable and usable.

Architecture Decisions

We made four architectural decisions early that shaped everything that followed. Each decision was a response to a specific failure mode we had observed in other documentation systems.

Decision One: Live Previews, Not Screenshots

Every component in the documentation is rendered inline as a live React component, not as a static screenshot. Screenshots go stale the moment a component is updated. They cannot be interacted with. They do not demonstrate hover states, focus rings, dark mode variants, or responsive behavior. A live preview does all of these things because it is the actual component, running in the actual environment, with the actual tokens applied.

The implementation uses a PreviewBox wrapper component that provides consistent padding, a labeled border, and optional background switching between light and dark modes. The preview renders server components by default, but wraps interactive components in a client boundary when needed.

preview-box.tsx
interface PreviewBoxProps {
  label: string
  description?: string
  children: React.ReactNode
  darkPreview?: boolean
}

function PreviewBox({ label, description, children, darkPreview }: PreviewBoxProps) {
  return (
    <div className="preview-box">
      <div className="preview-box-header">
        <span className="preview-box-label">{label}</span>
        {description && <span className="preview-box-desc">{description}</span>}
      </div>
      <div className={`preview-box-content ${darkPreview ? 'dark' : ''}`}>
        {children}
      </div>
    </div>
  )
}

Decision Two: Copy-Paste Ready Code Examples

Every component page includes code examples that can be copied and pasted directly into a project. Not pseudocode. Not simplified versions. Not examples that require the developer to figure out imports, props, and context on their own. The examples are complete, runnable, and tested against the current version of the component library.

This decision has a maintenance cost. When a component's API changes, the code examples must be updated. We accepted that cost because the alternative -- examples that do not work -- is worse than no examples at all. A developer who copies an example from documentation and gets an error has lost trust in the entire documentation system, not just the single example that failed.

Pseudocode in component documentation is a trust violation. If a developer cannot copy your example and have it work, the documentation has failed at its primary job.

Decision Three: Every Token Documented With Value and Usage

The token documentation page lists every CSS custom property in the system: its name, its current value, a visual swatch or preview, and its intended usage context. This is not generated from comments in the CSS. It is a maintained page that describes the semantic intent behind each token, not just its current value.

The distinction matters. --color-surface-elevated is not just "rgba(255, 255, 255, 0.05)". It is "the background color for elements that sit above the base surface, such as cards, modals, and dropdown menus." The value tells you what. The documentation tells you when and why. Without that context, developers choose tokens by visual matching, which breaks the moment the token value changes.

token-table.tsx
interface TokenRow {
  name: string
  value: string
  usage: string
  preview: React.ReactNode
}

function TokenTable({ tokens }: { tokens: TokenRow[] }) {
  return (
    <table className="token-table">
      <thead>
        <tr>
          <th>Token</th>
          <th>Value</th>
          <th>Preview</th>
          <th>Usage</th>
        </tr>
      </thead>
      <tbody>
        {tokens.map((t) => (
          <tr key={t.name}>
            <td><code>{t.name}</code></td>
            <td><code>{t.value}</code></td>
            <td>{t.preview}</td>
            <td>{t.usage}</td>
          </tr>
        ))}
      </tbody>
    </table>
  )
}

Decision Four: AI-Readable Markdown Twins

Every documentation page has a corresponding markdown variant accessible at the same route with an /md suffix. These markdown files are not simplified versions of the documentation. They contain the same information, structured for consumption by AI agents, code assistants, and automation tools.

This decision reflects a reality that most documentation systems have not yet acknowledged: AI agents are consumers of design system documentation. When a developer asks Claude or Copilot to "build a card component using our design system," the AI needs to find and read the card documentation. HTML pages optimized for human rendering are difficult for AI to parse. Markdown files with consistent structure are trivial.

The markdown twins follow a strict template: component name, description, props table, usage examples, do/don't guidance, and related components. This consistency means an AI agent can reliably extract what it needs from any component page without custom parsing logic.

AI agents are documentation consumers now. If your design system documentation is not machine-readable, you are excluding an increasingly important audience.

Implementation: Next.js App Router

The documentation site is built with Next.js App Router using server components for static generation. Each documentation page is a server component that imports the components it documents, renders them inline, and displays the associated code examples and token tables. There is no client-side JavaScript for pages that do not require interactivity.

directory-structure.txt
app/design/
  layout.tsx          # Shared sidebar + header
  page.tsx            # Overview / getting started
  colors/
    page.tsx          # Color token documentation
    md/route.ts       # Markdown twin (API route)
  typography/
    page.tsx          # Type scale documentation
    md/route.ts
  components/
    page.tsx          # Component index
    button/
      page.tsx        # Button docs + live preview
      md/route.ts
    card/
      page.tsx
      md/route.ts
    ...

The sidebar navigation is generated from the file system at build time. Adding a new component page requires creating a directory and a page.tsx file. The sidebar updates automatically on the next build. There is no manifest to maintain, no configuration file to update, and no risk that the navigation drifts from the actual content.

The Documentation Component Library

Documentation has its own component needs, distinct from the product component library. We built five components specifically for the documentation site.

1

PageHeader -- renders the page title, subtitle, and breadcrumb navigation. Accepts a category prop that determines the accent color.

2

PreviewBox -- wraps live component previews with a labeled border, description, and light/dark toggle.

3

CodeBlock -- syntax-highlighted code with a filename label, language indicator, and one-click copy button.

4

PropsTable -- renders a component's prop definitions as a table with name, type, default, and description columns.

5

Sidebar -- auto-generated navigation tree built from the file system at build time.

These five components cover the full surface area of component documentation. Every page is composed from the same building blocks, which ensures visual consistency and reduces the cognitive overhead of writing new documentation pages.

Lessons Learned

The most important lesson was that documentation is a product. It has users, requirements, bugs, and a maintenance burden. Treating it as a secondary artifact -- something you do after the real work is done -- guarantees that it will be incomplete, inaccurate, and eventually abandoned.

We schedule documentation updates alongside component work. When a component's API changes, the documentation PR is part of the same review. When a new token is added, the token page is updated before the token is used in production. This is not extra process. It is the minimum process required to keep documentation trustworthy.

The second lesson was that live previews catch bugs. Multiple times during development, rendering a component in the documentation surface revealed edge cases -- overflow behavior, missing dark mode styles, incorrect prop defaults -- that were not visible in the product context where the component was originally built. The documentation site became an unintentional integration test.

The third lesson was about audience. We assumed the documentation was for our team. In practice, it is also used by AI code assistants that our team relies on. The markdown twins were added after we observed AI agents struggling to parse the HTML documentation pages. The lesson generalized: know all of your users, including the non-human ones.


Design systems are infrastructure. Documentation is the interface to that infrastructure. Build the interface with the same rigor you apply to the system itself, or the system will not be used, no matter how well it was designed.

Key Takeaways

1

Live component previews in documentation prevent screenshots from going stale and enable interaction testing in context.

2

Copy-paste ready code examples are non-negotiable. Pseudocode erodes trust in the entire documentation system.

3

Token documentation must include semantic usage context, not just current values. Values change; intent persists.

4

AI-readable markdown twins make your design system accessible to code assistants and automation tools.

5

Documentation is a product with users, maintenance requirements, and a quality bar. Treat it accordingly.

Frequently Asked Questions

Common questions about this topic

The Content Pipeline: From Notion to Published in Four StagesMotion Design for AI Products: Less Is More

Related Articles

AI-Native Design

Why We Built a Design System for an AI Project

Most AI products look the same. We built a full design system with tokens, components, and principles to prove they don'...

AI-Native Design

Token-Based Theming: Why It Matters for AI-Generated UI

Design tokens enable consistent AI-generated interfaces. Here's how CSS custom properties create a machine-readable desi...

AI-Native Design

The Typography Stack: Why Font Choice Signals Product Quality

Typography is the first thing users feel, even if they can't name it. The relationship between type and trust in technic...

All Articles