Storybook

Build and document React components in isolation

📚 What is Storybook?

Storybook is a development environment for building, testing, and documenting UI components in isolation. It helps you develop components independently from your app, making development faster and more organized with visual testing capabilities.


# Initialize Storybook in your project
npx storybook@latest init

# Start Storybook
npm run storybook
                                    

Key Storybook Features

🔍

Component Isolation

Develop components independently

export default {
  component: Button
};
📖

Stories

Document component variations

export const Primary = {
  args: { label: 'Button' }
};
🎛️

Controls

Interactive prop editing

argTypes: {
  color: { control: 'color' }
}
🔌

Addons

Extend with powerful plugins

addons: [
  '@storybook/addon-essentials'
]

🔹 Installing Storybook

Add Storybook to your existing React project with automatic configuration. The CLI detects your project setup and installs the appropriate dependencies and configuration files.

# Install Storybook in existing project
npx storybook@latest init

# Start Storybook development server
npm run storybook

# Build static Storybook
npm run build-storybook

Storybook will run at http://localhost:6006

🔹 Project Structure

Storybook adds a .storybook directory for configuration and creates story files alongside your components. This keeps documentation close to the code it describes.

my-app/
├── .storybook/
│   ├── main.js          # Storybook configuration
│   └── preview.js       # Global decorators & parameters
├── src/
│   ├── components/
│   │   ├── Button.jsx
│   │   └── Button.stories.jsx  # Button stories
│   └── App.jsx
└── package.json

🔹 Creating Your First Story

Stories are written in CSF (Component Story Format) which exports component metadata and story variations. Each story represents a different state or use case of your component.

// src/components/Button.jsx
export default function Button({ label, onClick, variant = 'primary' }) {
  return (
    <button 
      onClick={onClick}
      className={`btn btn-${variant}`}
    >
      {label}
    </button>
  );
}

// src/components/Button.stories.jsx
import Button from './Button';

export default {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs']
};

export const Primary = {
  args: {
    label: 'Primary Button',
    variant: 'primary'
  }
};

export const Secondary = {
  args: {
    label: 'Secondary Button',
    variant: 'secondary'
  }
};

🔹 Story Args and Controls

Args define component props that can be edited interactively in Storybook. Controls automatically generate UI inputs for each arg, making it easy to test different prop combinations.

// Button.stories.jsx
export default {
  title: 'Components/Button',
  component: Button,
  argTypes: {
    label: { control: 'text' },
    variant: {
      control: 'select',
      options: ['primary', 'secondary', 'danger']
    },
    disabled: { control: 'boolean' },
    size: {
      control: 'radio',
      options: ['small', 'medium', 'large']
    }
  }
};

export const Interactive = {
  args: {
    label: 'Click me',
    variant: 'primary',
    disabled: false,
    size: 'medium'
  }
};

🔹 Multiple Stories

Create multiple stories to showcase different component states and variations. This helps document all possible use cases and makes testing edge cases easier.

// Card.stories.jsx
import Card from './Card';

export default {
  title: 'Components/Card',
  component: Card
};

export const Default = {
  args: {
    title: 'Card Title',
    content: 'This is the card content.'
  }
};

export const WithImage = {
  args: {
    title: 'Card with Image',
    content: 'Card content here',
    image: 'https://via.placeholder.com/300'
  }
};

export const Loading = {
  args: {
    title: 'Loading...',
    isLoading: true
  }
};

export const Error = {
  args: {
    title: 'Error',
    error: 'Something went wrong!'
  }
};

🔹 Decorators

Decorators wrap stories with extra markup or context providers. Use them to add themes, routing, or state management to your component stories.

// Add decorator to single story
export const Centered = {
  args: { label: 'Button' },
  decorators: [
    (Story) => (
      <div style={{ display: 'flex', justifyContent: 'center' }}>
        <Story />
      </div>
    )
  ]
};

// Add decorator to all stories in file
export default {
  title: 'Components/Button',
  component: Button,
  decorators: [
    (Story) => (
      <div style={{ padding: '3rem' }}>
        <Story />
      </div>
    )
  ]
};

🔹 Global Decorators

Apply decorators to all stories globally through the preview configuration. Perfect for adding theme providers, routers, or global styles to every story.

// .storybook/preview.js
import { ThemeProvider } from 'styled-components';
import { theme } from '../src/theme';

export const decorators = [
  (Story) => (
    <ThemeProvider theme={theme}>
      <Story />
    </ThemeProvider>
  )
];

// With React Router
import { BrowserRouter } from 'react-router-dom';

export const decorators = [
  (Story) => (
    <BrowserRouter>
      <Story />
    </BrowserRouter>
  )
];

🔹 Actions Addon

The Actions addon logs component events in the Storybook UI. It helps you verify that event handlers are called correctly with the right arguments.

import { action } from '@storybook/addon-actions';

export default {
  title: 'Components/Button',
  component: Button
};

export const WithActions = {
  args: {
    label: 'Click me',
    onClick: action('button-clicked')
  }
};

// Multiple actions
export const Form = {
  args: {
    onSubmit: action('form-submitted'),
    onChange: action('input-changed'),
    onFocus: action('input-focused')
  }
};

🔹 Documentation

Storybook automatically generates documentation from your stories and component props. Add MDX files for custom documentation with interactive examples embedded inline.

// Button.stories.jsx
export default {
  title: 'Components/Button',
  component: Button,
  tags: ['autodocs'], // Auto-generate docs
  parameters: {
    docs: {
      description: {
        component: 'A versatile button component with multiple variants.'
      }
    }
  }
};

// Custom MDX documentation
// Button.mdx
import { Meta, Story, Canvas } from '@storybook/blocks';
import * as ButtonStories from './Button.stories';

<Meta of={ButtonStories} />

# Button Component

A reusable button component.

<Canvas of={ButtonStories.Primary} />

🔹 Essential Addons

Storybook addons extend functionality with tools for accessibility testing, responsive design, and more. The essentials addon bundle includes the most commonly used addons.

# Essentials addon (included by default)
# Includes: docs, controls, actions, viewport, backgrounds, toolbars
// .storybook/main.js
export default {
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-a11y', // Accessibility testing
    '@storybook/addon-interactions' // Interaction testing
  ]
};

// Using viewport addon
export const Mobile = {
  args: { label: 'Button' },
  parameters: {
    viewport: {
      defaultViewport: 'mobile1'
    }
  }
};

🔹 Complete Example

A comprehensive example showing a component with multiple stories, controls, actions, and documentation. This demonstrates best practices for component documentation.

// src/components/Alert.jsx
export default function Alert({ 
  type = 'info', 
  title, 
  message, 
  onClose 
}) {
  return (
    <div className={`alert alert-${type}`}>
      <h3>{title}</h3>
      <p>{message}</p>
      {onClose && (
        <button onClick={onClose}>Close</button>
      )}
    </div>
  );
}

// src/components/Alert.stories.jsx
import { action } from '@storybook/addon-actions';
import Alert from './Alert';

export default {
  title: 'Components/Alert',
  component: Alert,
  tags: ['autodocs'],
  argTypes: {
    type: {
      control: 'select',
      options: ['info', 'success', 'warning', 'error']
    }
  }
};

export const Info = {
  args: {
    type: 'info',
    title: 'Information',
    message: 'This is an informational message.',
    onClose: action('close-clicked')
  }
};

export const Success = {
  args: {
    type: 'success',
    title: 'Success!',
    message: 'Operation completed successfully.'
  }
};

export const Error = {
  args: {
    type: 'error',
    title: 'Error',
    message: 'Something went wrong.'
  }
};

🧠 Test Your Knowledge

What is the default port for Storybook?