Storybook is the industry standard for building and documenting UI components in isolation. When used correctly, it eliminates entire categories of bugs that only appear in edge cases — empty states, loading states, error states, long strings, missing data.
What Storybook Actually Solves
Without Storybook:
- You discover the "empty state" bug in production
- You can't test error states without triggering real errors
- New developers can't see what components are available
- Design reviews happen in production, not in isolation
With Storybook:
- Every component state is testable in isolation
- Non-developers can review UI without running the app
- Components become the source of truth for the design system
Setup with Next.js
npx storybook@latest init
This detects Next.js and configures everything automatically.
Writing Stories
// components/ui/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './button'
const meta: Meta<typeof Button> = {
title: 'UI/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'destructive', 'outline', 'ghost'],
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
},
},
}
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: { children: 'Click me' },
}
export const Destructive: Story = {
args: { variant: 'destructive', children: 'Delete' },
}
export const Loading: Story = {
args: { loading: true, children: 'Saving...' },
}
export const Disabled: Story = {
args: { disabled: true, children: 'Unavailable' },
}
Complex Component Stories
// components/ProductCard.stories.tsx
export const Default: Story = {
args: {
product: {
id: '1',
name: 'MCP Security Scanner',
price: 29,
description: 'Audit any MCP server for vulnerabilities',
image: '/product.jpg',
},
},
}
export const LongTitle: Story = {
args: {
product: {
...Default.args.product,
name: 'This Is A Very Long Product Name That Might Overflow The Card Layout',
},
},
}
export const NoImage: Story = {
args: {
product: { ...Default.args.product, image: undefined },
},
}
export const Loading: Story = {
args: { isLoading: true },
}
Testing edge cases (long titles, missing images) before they reach production.
Interaction Testing
import { within, userEvent } from '@storybook/testing-library'
import { expect } from '@storybook/jest'
export const FormSubmit: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement)
// Fill in the form
await userEvent.type(canvas.getByLabelText('Email'), 'test@example.com')
await userEvent.type(canvas.getByLabelText('Password'), 'password123')
// Submit
await userEvent.click(canvas.getByRole('button', { name: 'Sign in' }))
// Assert
await expect(canvas.getByText('Loading...')).toBeInTheDocument()
},
}
Accessibility Testing
npm install @storybook/addon-a11y
The a11y addon runs axe-core on every story automatically. Accessibility violations show up in the Storybook UI — fix them before they reach production.
Visual Regression Testing
# Chromatic -- cloud service, integrates with CI
npm install -g chromatic
chromatic --project-token=$CHROMATIC_TOKEN
Every PR shows visual diffs of every component story. Catch unintended visual changes before merge.
Running in CI
# .github/workflows/storybook.yml
- name: Build Storybook
run: npm run build-storybook
- name: Run interaction tests
run: npx concurrently -k -s first "npx http-server storybook-static" "npx wait-on tcp:8080 && npx playwright test"
The AI SaaS Starter at whoffagents.com ships with Storybook configured, stories for all 15 shadcn/ui components, and interaction tests for forms. $99 one-time.
Top comments (0)