Design System Documentation: Storybook, Zeroheight and Custom Docs
Compare Storybook, Zeroheight and custom docs for your design system. Learn when to use each, how to combine them, and what teams actually ship in 2026.
Why Documentation Is the Part Everyone Procrastinates On
You've built a solid component library. Buttons, cards, modals, a color token system that actually makes sense. Then someone on the team asks "where's the docs?" and suddenly you're writing a README at 11pm hoping it answers all the questions it won't. Sound familiar?
Documentation is the thing that separates a collection of components from an actual design system. Without it, developers copy-paste from Figma, designers invent new variants that already exist, and onboarding a new hire takes three days instead of three hours. The cost of bad docs isn't dramatic — it's just slow, grinding friction that compounds over months.
In 2026 there are three serious options for documenting a component library: Storybook (developer-first, interactive), Zeroheight (design-dev bridge, polished), and custom documentation built in-house (maximum control, maximum effort). None of them is universally correct. The right pick depends on your team size, your Figma relationship, and honestly how much time you can actually commit to maintaining the thing.
Worth noting: most mature teams end up running two of these in parallel — Storybook for engineers and something else for the design-to-dev handoff. That's not a failure, it's just reality.
Storybook: The Developer's Default
Storybook 8.x is genuinely good. The addon ecosystem has matured, the Vite builder is fast, and the Controls panel makes it trivial to demo every prop variation without writing a dedicated test page. If your team is primarily engineers and you want a zero-ceremony way to isolate and document components, Storybook is probably the right starting point.
The setup is straightforward. You write stories alongside your components, and Storybook renders them in an iframe sandbox. Each story is basically a named export from a .stories.tsx file. Here's a minimal example for a design-token-aware button:
``tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './Button'
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
args: {
variant: 'primary',
size: 'md',
},
}
export default meta
type Story = StoryObj<typeof Button>
export const Primary: Story = {}
export const Ghost: Story = {
args: { variant: 'ghost' },
}
``
That's it. Storybook infers the prop types from TypeScript and surfaces them as interactive controls automatically.
Honestly, the biggest limitation isn't the tool — it's the cultural gap. Designers rarely use Storybook. The URL localhost:6006 means nothing to a Figma-native designer. You can deploy it to a URL and share it, but the interface looks like a dev tool because it is one. Don't expect your design team to navigate the sidebar tree and click through variants while comparing them to their comps.
That said, Storybook's @storybook/addon-a11y plugin is genuinely worth enabling from day one. It runs axe-core on every story and flags contrast failures, missing aria attributes, and focus order issues directly in the UI. If you're building on top of components like the ones in the Empire UI, having automated a11y checks baked into your docs workflow catches issues before they reach review.
One more thing — Storybook's interaction testing via @storybook/test and the play function turns stories into lightweight integration tests. You can simulate a user clicking a dropdown, typing in an input, and assert the result. It's not a replacement for Playwright, but it's useful for catching visual regressions on documented states.
Zeroheight: When Designers Need to Read the Docs Too
Zeroheight sits in a different lane entirely. It's a documentation platform that pulls from Figma (via plugin) and lets you embed live components alongside design specs on the same page. The pitch is a single source of truth that designers and developers both actually use. In practice, it delivers on that about 70% of the way.
Setup involves connecting your Figma file, then building pages in Zeroheight's editor. You embed Figma frames to show design intent, add code snippets manually (or link a Storybook embed), and write guidelines in a rich-text editor. Pages look polished — more like a product documentation site than a dev tool. The Airbnb, Shopify, and Atlassian design teams have all shipped with it, which gives you a reasonable confidence signal.
The weak spot is the live component story. Zeroheight doesn't render your actual React components in a sandbox the way Storybook does. You can embed a Storybook iframe, which works, but it's two systems in a trench coat. Keeping Figma frames, Zeroheight pages, and Storybook stories in sync across three tools adds maintenance overhead that small teams feel fast. If you have fewer than four people maintaining the system, that overhead matters.
Pricing is the other conversation. Zeroheight's free tier is limited to one styleguide, and the paid plans start at $149/month per styleguide as of 2026. That's not outrageous for a 20-person product team, but it's real money for a startup or an open-source project. Quick aside: if you're building a UI library inspired by a specific aesthetic — say you're documenting a glassmorphism components system or a neobrutalism kit — the visual quality of Zeroheight pages makes the components look intentional. That matters when you're pitching the design system internally.
In practice, Zeroheight works best when you already have a dedicated design systems team and an established Figma component library. If your Figma components are still inconsistent or your tokens aren't finalized, you'll spend more time updating Zeroheight pages than building components. Get the foundation right first.
Custom Documentation: Full Control, Real Cost
Some teams build their own documentation site. Next.js, MDX, a component preview system, and a search index. It's more work than you'd expect and less glamorous than it sounds, but it gives you things neither Storybook nor Zeroheight can: complete control over the URL structure, the ability to embed real production components (not iframe sandboxes), and the freedom to design the docs to match your brand.
The component preview problem is where most custom docs systems spend their time. You need an isolated rendering environment, but you want it to feel native to the page. A common pattern is a <LivePreview> component that takes a JSX string, transforms it with Sucrase or the Babel standalone build, and renders it directly in the page:
``tsx
import { transform } from 'sucrase'
import { useState, useCallback } from 'react'
export function LivePreview({ code }: { code: string }) {
const [error, setError] = useState<string | null>(null)
const Preview = useCallback(() => {
try {
const { code: transformed } = transform(code, {
transforms: ['jsx', 'typescript'],
})
// eslint-disable-next-line no-new-func
const fn = new Function('React', return (${transformed}))
return fn(React)
} catch (e) {
setError((e as Error).message)
return null
}
}, [code])
if (error) return <pre className="text-red-500 text-sm">{error}</pre>
return <Preview />
}
``
That approach works but has security implications — you're eval-ing user-supplied code. In a private docs site it's fine. In a public playground you'd want a sandboxed iframe with postMessage.
MDX is the other half of the equation. It lets you write documentation in Markdown with embedded React components, which means you can write prose that flows naturally and drop in a live example exactly where it makes sense. Most Next.js-based doc sites use next-mdx-remote or Contentlayer (now Velite) to process MDX at build time.
The real cost of custom docs isn't the build — it's the ongoing maintenance. Who updates the docs when a component's API changes? If there's no automated connection between your component source and the documentation, it drifts. Storybook sidesteps this because stories live next to the component. Custom docs need a discipline decision: either co-locate MDX files with components, or accept that the docs will fall behind. Look, most teams that build custom docs initially underestimate how much work this is by about 3x.
Where custom docs genuinely shine is for design systems with strong brand requirements. If you're building a full-featured component library — maybe one that documents aurora gradient backgrounds alongside code examples — your docs site can be as opinionated and styled as you want. That's not possible inside Storybook's chrome or Zeroheight's templates.
Token Documentation: The Layer Everyone Forgets
Whatever documentation system you choose, you need a dedicated section for design tokens. Not a table of hex values buried in a README — actual rendered swatches with usage context. This is where most design system docs fall short.
At minimum, your token docs should show every color in context, not just as a swatch. A 4px border on a white card looks different from a 4px border on a dark surface. Your typography tokens should render as actual text samples at the documented font-size, not just list values like --text-lg: 1.125rem. Here's a minimal token display component:
``tsx
function ColorToken({ name, value, description }: {
name: string
value: string
description: string
}) {
return (
<div className="flex items-center gap-4 p-3 rounded-lg border border-zinc-800">
<div
className="w-12 h-12 rounded-md flex-shrink-0"
style={{ background: value }}
/>
<div>
<code className="text-sm font-mono">{name}</code>
<p className="text-zinc-400 text-xs mt-0.5">{description}</p>
<p className="text-zinc-500 text-xs">{value}</p>
</div>
</div>
)
}
``
Shadow tokens are trickier to document well. A shadow value like 0 4px 24px rgba(0,0,0,0.12) means nothing until you see it on a card component. If you're building a system with glassmorphism components or neumorphism effects, the shadow is literally half the component — documenting it as a CSS string without the visual is almost useless. Show the rendered output, always.
One pattern worth stealing from Tailwind's docs: every token page should show the CSS variable name, the raw value, and a "when to use" note in plain English. Not "use for elevated surfaces" — something like "use this shadow on modals and dropdowns that float above page content, not on inline cards." That specificity is what prevents designers from inventing a new shadow variant every sprint.
Running Two Systems in Parallel (Without Going Insane)
Most teams settle on Storybook for component development and testing, plus either Zeroheight or a custom site for the higher-level guidelines, token documentation, and usage patterns. The challenge is keeping them from diverging. Here's what actually works.
First, make Storybook the authoritative source for interactive component demos. Don't duplicate the interactive controls in your custom docs — embed the Storybook iframe for the parts that need user interaction. This keeps the rendered component output in one place. If a component changes, the Storybook story reflects it automatically, and your embed picks it up.
Second, use your custom docs or Zeroheight for the conceptual layer: when to use a component, which variant fits which context, accessibility notes, and the reasoning behind design decisions. Storybook is terrible at this. A wall of props controls doesn't explain that the destructive button variant should only appear in confirmation dialogs, never in navigation. That judgment lives in prose, not in code.
Third — and this one takes discipline — treat documentation as part of the definition of done. A component isn't shipped until it has a story, a usage note, and a token reference. If your team is small, a simple checklist in your PR template works. If you're on a larger team, a linting rule that warns on undocumented exported components (via a custom ESLint plugin or a Danger.js check) makes it structural rather than voluntary.
Worth noting: the gradient generator and box shadow generator tools on Empire UI are good examples of docs-adjacent tooling that lives alongside a component library. They're not documentation in the traditional sense, but they reduce the "how do I produce this value?" question that eats up time in design reviews. Interactive tools that output copy-paste values are underrated as documentation.
Choosing the Right Setup for Your Team Size
Solo developer or tiny startup (1-3 people): Start with Storybook and a solid README. Don't build a custom docs site — you won't maintain it. Focus on writing good stories with thorough descriptions in the parameters.docs object. Storybook Autodocs generates a props table automatically from TypeScript types, which covers 80% of what a small team needs.
Mid-size product team (4-15 people): Storybook plus Zeroheight is the combination that works here. The design team gets a readable interface in Zeroheight, engineers work in Storybook, and you set a weekly reminder to sync Figma frames into Zeroheight. The $149/month is justified once it replaces even two Slack threads per week about "which variant should I use?"
Larger team or design system as a product (15+ people): This is where a custom documentation site starts to make sense. You need versioning (showing docs for v2.x and v3.x simultaneously), search that understands your token naming convention, and the ability to document migration paths. That's hard to do in Zeroheight and awkward in Storybook. Next.js with MDX, Algolia DocSearch, and a version switcher is the typical stack. Expect 4-6 weeks to build something genuinely good.
One thing cuts across all team sizes: whoever writes the documentation needs to actually use the components. Docs written by someone who read the source code are measurably worse than docs written by someone who tried to build a feature with the component and hit the rough edges. Rotate the documentation responsibility, or at minimum have the person writing docs do a quick implementation spike first.
FAQ
Yes, and many teams do. Embed Storybook iframes inside Zeroheight pages for live component demos, while using Zeroheight for usage guidelines and Figma specs. It's two tools, but they cover different audiences without much duplication.
Not really. Storybook is excellent for component isolation and prop exploration, but it's a dev tool — designers rarely use it. You'll still need something friendlier for guidelines, tokens, and design decisions.
Use the @storybook/addon-designs plugin for Figma links, and write a dedicated Docs page using MDX that renders token swatches as components. There's no built-in token view in Storybook — you have to build it yourself.
A Storybook with one story per exported component, a README covering installation and theming, and a color/token reference in any format. That baseline lets a new developer be productive without Slack questions on day one.