Generate Storybook Stories with AI in 15 Minutes

Use Claude or ChatGPT to auto-generate Storybook stories for your React/Vue components with proper controls and variants.

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/test not @testing-library/react
  • Use within(canvasElement) not screen

Tested on Storybook 8.3, React 18.3, TypeScript 5.5, Claude Sonnet 4