Next.js starter your AI actually understands. Ship internal tools in days not weeks. Pre-order $199 $499 → [Get it now]

How to use Storybook in React

Building complex user interfaces requires a strategy that prioritizes isolation and predictability.
With over 25 years of experience in software development and as the creator of CoreUI, I’ve built thousands of components that rely on robust documentation and visual testing.
The most efficient and modern solution for managing component lifecycles in React is to implement Storybook, which enables Component-Driven Development (CDD).
By using Storybook, you can develop components without worrying about application-specific logic, APIs, or data structures.

Use the Storybook CLI to initialize the environment and create .stories.jsx files to define component states.

npx storybook@latest init

Storybook transforms your development workflow by providing a sandbox where you can interact with your React components. Instead of navigating through your entire application to verify a specific UI state, you create “stories” that represent those states. This is exactly how we maintain the high standards of the CoreUI React components.

1. Initializing Storybook in Your Project

The first step is to integrate the Storybook architecture into your existing React application. The automated initializer detects your framework and sets up the necessary configuration files, dependencies, and scripts.

# Execute this in your React project root
npx storybook@latest init

This command creates a .storybook directory for configuration and a src/stories directory with examples. It also adds two scripts to your package.json: storybook for local development and build-storybook for generating a static documentation site. This setup ensures that your UI library remains decoupled from the main application logic.

2. Creating a Basic Story for a Component

Once initialized, you define stories by exporting a default object that describes the component and named exports for each visual state. Here is how you create a story for a standard CoreUI Button.

import React from 'react'
import { CButton } from '@coreui/react'

export default {
  title: 'Components/CButton',
  component: CButton,
}

export const Primary = () => <CButton color='primary'>Primary Button</CButton>
export const Secondary = () => <CButton color='secondary'>Secondary Button</CButton>

In this example, the title determines where the component appears in the Storybook sidebar. Each named export becomes a selectable “story” in the UI. This approach is perfect when you need to capitalize the first letter of a string for dynamic labels or verify how long text wraps within a button.

3. Utilizing Args for Dynamic Interaction

The Args pattern is the modern way to write stories. It allows you to pass props dynamically to your components through the Storybook “Controls” panel without rewriting the JSX for every variation.

import { CButton } from '@coreui/react'

export default {
  title: 'CoreUI/Button',
  component: CButton,
  argTypes: {
    color: {
      control: { type: 'select' },
      options: ['primary', 'secondary', 'success', 'danger', 'warning', 'info'],
    },
  },
}

export const DynamicButton = {
  args: {
    color: 'primary',
    children: 'Click Me',
    disabled: false,
  },
}

By using the CSF3 object syntax, you define each story as a plain object with an args property. This allows developers to test edge cases, such as how a button renders when you need to format a number as currency inside a label, directly in the browser.

4. Implementing Decorators for Context

Decorators are wrapper components that provide context to your stories, such as themes, providers, or specific layout constraints like padding and margins. They are essential for components that rely on external state or specific DOM hierarchies.

import React from 'react'
import { CCard, CCardBody } from '@coreui/react'

export default {
  title: 'Layout/DecoratedCard',
  component: CCard,
  decorators: [
    (Story) => (
      <div style={{ padding: '3rem', backgroundColor: '#f8f9fa' }}>
        <Story />
      </div>
    ),
  ],
}

export const DefaultCard = () => (
  <CCard>
    <CCardBody>This card is centered via a decorator.</CCardBody>
  </CCard>
)

In CoreUI templates, we use decorators to ensure components are always rendered within the correct theme provider or grid system. This ensures that the visual representation in Storybook perfectly matches the final production environment.

5. Handling Component Actions and Events

Storybook’s Actions addon allows you to verify that your event handlers are firing correctly with the expected arguments. This is crucial for interactive elements like forms, toggles, or custom inputs.

import { CButton } from '@coreui/react'

export default {
  title: 'Events/ButtonClicks',
  component: CButton,
  argTypes: {
    onClick: { action: 'clicked' },
  },
}

export const LoggedButton = {
  args: {
    color: 'info',
    children: 'Check the Actions Tab',
  },
}

When you click the button in the Storybook UI, the “Actions” panel logs the event data. This validates that your component is correctly passing props to the underlying DOM elements, ensuring reliability in complex React Dashboard Templates.

6. Interaction Testing with the Play Function

The play function allows you to write automated interaction tests directly within your stories. It uses Testing Library under the hood to simulate user behavior, ensuring that components behave as expected after rendering.

import { userEvent, within } from '@storybook/test'
import { CButton } from '@coreui/react'

export default {
  title: 'Testing/InteractiveButton',
  component: CButton,
}

export const ClickTest = {
  args: {
    color: 'success',
    children: 'Submit',
  },
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement)
    const submitButton = await canvas.getByRole('button', { name: /Submit/i })
    await userEvent.click(submitButton)
  },
}

The play function executes immediately after the story finishes rendering. This is a powerful way to document complex behaviors, such as confirming a Modal opens correctly or a form validates input as expected before it ever reaches the main application code.

Best Practice Note:

Always keep your stories in the same folder as your component files (e.g., Button.jsx and Button.stories.jsx). This makes it easier to maintain the documentation as the component evolves. At CoreUI, we treat stories as the “source of truth” for UI behavior. For large-scale projects, consider using MDX (Markdown with JSX) in Storybook to combine rich text documentation with live component examples, providing a comprehensive design system for your team.


Speed up your responsive apps and websites with fully-featured, ready-to-use open-source admin panel templates—free to use and built for efficiency.


About the Author