The Documentation Gap
The shared-ui library had 37 components, a cn() utility, error boundaries,
and a theme with 100+ design tokens defined in CSS custom properties. It also
had a README that said:
Shared React component library.
That's it. One line.
Anyone consuming the library had to read the source code to discover
the available tokens, understand component APIs, or learn the conventions.
Every question, like "what's the text-tertiary color?" or "is there a card variant
for elevated surfaces?", meant grepping through theme.css.
Docs Are Part of the Design System
A component library without documentation is a codebase, not a design system.
The distinction matters because a design system encodes decisions, not just
code. When you choose text-text-secondary for body text, that's a decision;
when a developer guesses text-gray-500 because they don't know the token
exists, the decision is lost.
Documentation captures three things the code alone can't:
- Intent: Why
text-text-secondaryexists and when to use it - Constraints: What's available and what's off-limits
- Patterns: How tokens compose into common UI recipes
The Token Reference Structure
I organized the theme documentation around usage categories rather than implementation details, because developers think "I need a muted text color," not "I need an oklch value":
Color Tokens
Surface colors:
--color-surface → Base background
--color-surface-secondary → Card/section backgrounds
--color-surface-elevated → Elevated cards, modals
--color-surface-tertiary → Subtle backgrounds (input fields, code blocks)
Text colors:
--color-text-primary → Headings, primary content
--color-text-secondary → Body text, descriptions
--color-text-tertiary → Metadata, timestamps, hints
--color-text-inverse → Text on dark backgrounds
Border colors:
--color-border → Default borders
--color-border-secondary → Emphasized borders (hover states)
Each token includes light and dark mode values, so nobody has to remember oklch values; they just pick the semantic token that matches their intent.
Typography Tokens
Rather than listing font sizes, I documented the variant components:
| Use case | Component | Output |
|---|---|---|
| Page hero | <Heading variant="hero"> | 36px → 48px responsive, bold |
| Card title | <Heading variant="cardTitle"> | 14px, semibold |
| Body text | <Text variant="body"> | 14px, secondary color |
| Metadata | <Text variant="meta"> | 12px, tertiary color |
That bridges the gap between "I need small gray text" and "use
<Text variant='meta'>."
Component Catalog
Each component gets a consistent entry:
### Alert
Status messages with contextual styling.
**Variants:** `info` | `success` | `warning` | `error`
**Props:** `title?`, `dismissible?`, `onDismiss?`
Usage:
<Alert variant="warning" title="Heads up">
Check your input values.
</Alert>Key decisions are called out explicitly: "Alert title uses text-sm font-semibold with margin reset. The body uses text-sm text-text-secondary."
Contribution Guidelines
The README includes rules for adding new components:
- No Next.js dependencies: shared-ui depends only on React + Tailwind
- Use
Heading/Textfor all typography: no rawtext-*+font-* - Accept
refas a regular prop (React 19 pattern, notforwardRef) - Accept
classNamefor style extensions viacn()merging - Export types alongside components from the barrel index
These rules keep the library from drifting back toward the inconsistent state I started in.
The Impact
After I shipped the full README:
- Onboarding friction dropped: new components follow the documented patterns instead of cargo-culting from existing code
- Token adoption went up: developers reach for
text-text-tertiaryinstead of guessing gray values - PR reviews got faster: reviewers point at the docs instead of explaining conventions from memory
Documentation isn't a nice-to-have; it's the interface between your design decisions and the developers who implement them. Without it, every decision lives in one person's head, and that doesn't scale.
