Problem: Writing Storybook Stories Takes Forever
You have 50+ components in your UI library but writing Storybook stories manually is eating up sprint time. Each component needs multiple variants, controls, and documentation.
You'll learn:
- How to generate stories from component code
- Prompt patterns that work with Claude/ChatGPT
- Auto-generating args and controls
- Batch processing multiple components
Time: 15 min | Level: Intermediate
Why This Works Now
Storybook 8+ uses CSF 3.0 (Component Story Format) which is highly structured and predictable - perfect for AI generation. Modern LLMs understand TypeScript interfaces and can infer prop types automatically.
Common scenarios:
- Migrating from CSF 2.0 to 3.0
- Documenting legacy component libraries
- Generating stories for design system components
- Creating consistent story patterns across teams
Solution
Step 1: Install Storybook CLI (if needed)
# For existing projects
npx storybook@latest upgrade
# Verify version (need 8.0+)
npm list @storybook/react
Expected: Version 8.0.0 or higher
Step 2: Create the AI Prompt Template
Save this as storybook-prompt.md in your project:
Generate a Storybook CSF 3.0 story for this component.
COMPONENT CODE:
[paste component here]
REQUIREMENTS:
- Use CSF 3.0 format with Meta and StoryObj types
- Infer all props from TypeScript interface
- Create 3-5 realistic variants (Default, WithX, EdgeCase)
- Add argTypes with proper controls
- Include JSDoc comments for each story
- Use play function for interaction testing if component has events
OUTPUT FORMAT:
- Single .stories.tsx file
- No explanations, just code
- Use component name for filename
Why this works: Specific format requirements prevent AI from adding unnecessary context. The structure matches Storybook 8 conventions.
Step 3: Generate Your First Story
// Example: Button.tsx component
interface ButtonProps {
variant: 'primary' | 'secondary' | 'danger';
size: 'sm' | 'md' | 'lg';
disabled?: boolean;
onClick?: () => void;
children: React.ReactNode;
}
export const Button: React.FC<ButtonProps> = ({ ... }) => { ... }
Paste into Claude/ChatGPT with the prompt template.
AI Output:
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { fn } from '@storybook/test';
import { Button } from './Button';
const meta = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger'],
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
},
disabled: {
control: 'boolean',
},
},
args: {
onClick: fn(), // Auto-spy for Actions panel
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
/**
* Default primary button
*/
export const Default: Story = {
args: {
variant: 'primary',
size: 'md',
children: 'Click me',
},
};
/**
* Secondary variant for less emphasis
*/
export const Secondary: Story = {
args: {
variant: 'secondary',
size: 'md',
children: 'Secondary action',
},
};
/**
* Danger state for destructive actions
*/
export const Danger: Story = {
args: {
variant: 'danger',
size: 'md',
children: 'Delete',
},
};
/**
* Disabled state prevents interaction
*/
export const Disabled: Story = {
args: {
variant: 'primary',
size: 'md',
disabled: true,
children: 'Disabled',
},
};
/**
* Small size for compact UIs
*/
export const Small: Story = {
args: {
variant: 'primary',
size: 'sm',
children: 'Small button',
},
};
Step 4: Batch Process Multiple Components
Create generate-stories.sh:
#!/bin/bash
# Loop through all components
for file in src/components/**/*.tsx; do
# Skip if .stories.tsx already exists
story_file="${file%.tsx}.stories.tsx"
if [ -f "$story_file" ]; then
echo "⏭️ Skipping $file (story exists)"
continue
fi
echo "🤖 Generating story for $file"
# Copy component code to clipboard (macOS)
cat "$file" | pbcopy
# Prompt user to paste into AI
echo "📋 Component copied to clipboard"
echo "1. Paste into Claude with prompt template"
echo "2. Copy AI output"
echo "3. Press Enter to save..."
read
# Paste AI output from clipboard
pbpaste > "$story_file"
echo "✅ Saved to $story_file"
echo ""
done
For Linux/WSL: Replace pbcopy/pbpaste with xclip or wl-copy
Step 5: Refine with Advanced Patterns
For complex components with interactions:
ADDITIONAL REQUIREMENT:
Add a play function to test user interactions:
- Click events
- Form submissions
- Hover states
- Keyboard navigation
Example play function:
```typescript
export const Interactive: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button');
await userEvent.click(button);
await expect(button).toHaveAttribute('aria-pressed', 'true');
},
};
**AI will generate:**
```typescript
import { expect, userEvent, within } from '@storybook/test';
export const WithInteraction: Story = {
args: {
variant: 'primary',
children: 'Interactive',
},
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button');
// Test click interaction
await userEvent.click(button);
await expect(button).toHaveFocus();
},
};
Verification
# Run Storybook
npm run storybook
# Test stories
npm run test-storybook
You should see:
- All components render in sidebar
- Controls panel shows correct prop types
- Interactions tab shows play function results
- No TypeScript errors
Advanced: Component Analysis Prompt
For components without clear TypeScript types:
Analyze this component and:
1. Infer prop types from usage
2. Identify all variants from className logic
3. List all possible states (loading, error, success)
4. Generate comprehensive stories covering edge cases
COMPONENT:
[paste component]
OUTPUT: Complete TypeScript interface + stories
This works for:
- JavaScript components (AI infers types)
- Legacy class components
- Components with complex state logic
What You Learned
- AI excels at structured, predictable formats like CSF 3.0
- Specific prompts (no explanations, exact format) get better results
- Batch processing saves hours on large component libraries
- Play functions can be auto-generated for interaction tests
Limitations:
- AI can't test component behavior - verify generated stories work
- Complex state machines may need manual adjustment
- Custom decorators/parameters require prompt refinement
When NOT to use:
- One-off components (faster to write manually)
- Components with external dependencies AI can't see
- Highly dynamic render logic based on runtime data
Bonus: GitHub Copilot Integration
If you use Copilot, add this to .github/copilot-instructions.md:
## Storybook Story Generation
When creating .stories.tsx files:
- Use CSF 3.0 format
- Include Meta and StoryObj types
- Add argTypes for all props
- Create 3-5 variants minimum
- Use fn() for action handlers
- Add JSDoc comments to each story
- Include play functions for interactive components
Result: Copilot will suggest story code as you type, following your team's conventions.
Common Issues
Error: "satisfies is not defined"
- Update TypeScript to 4.9+
- Check tsconfig:
"target": "ES2022"or higher
Stories don't show controls:
- Verify argTypes match prop names exactly
- Check component uses typed props (not
any)
Play functions fail:
- Import
@storybook/testnot@testing-library/react - Use
within(canvasElement)notscreen
Tested on Storybook 8.3, React 18.3, TypeScript 5.5, Claude Sonnet 4