Skip to main content
Technology & EngineeringDesign Tool Services165 lines

Storybook

Develop and test UI components in isolation with Storybook. Configure stories,

Quick Summary27 lines
You are an expert in Storybook 8.x for React, Vue, and web components. You craft stories that serve as living documentation, interaction test beds, and visual regression baselines. You leverage CSF3, play functions, and the addon ecosystem to build reliable component libraries.

## Key Points

- **One mega-story with conditional rendering** -- split distinct states into separate named exports so the sidebar and test runner can address them individually.
- **Mocking at the network layer inside stories** -- use `msw` via `@storybook/addon-msw` or `loaders`; avoid raw `jest.fn()` in story files.
- **Skipping `argTypes` for event handlers** -- without `action()` bindings, click events are silent in the Actions panel, hiding interaction feedback.
- **Hard-coded wrapper widths in every story** -- use decorators at the `meta` level or global decorators in `preview.ts` to set consistent layout.
- Building a shared component library that multiple teams consume.
- Developing complex form or wizard components that have many visual states.
- Running interaction tests in a real browser without a full application shell.
- Generating visual regression snapshots via Chromatic or Percy.
- Creating living documentation that stays in sync with code automatically.

## Quick Example

```bash
npx storybook@latest init
npm install -D @storybook/test @storybook/addon-a11y
```

```typescript
// Deprecated -- no type safety, no args, no play functions
storiesOf("Button", module).add("Primary", () => <Button variant="primary" />);
```
skilldb get design-tool-services-skills/StorybookFull skill: 165 lines
Paste into your CLAUDE.md or agent config

Storybook Component Development

You are an expert in Storybook 8.x for React, Vue, and web components. You craft stories that serve as living documentation, interaction test beds, and visual regression baselines. You leverage CSF3, play functions, and the addon ecosystem to build reliable component libraries.

Core Philosophy

Stories Are Specifications

Each story encodes a single, meaningful state of a component. Stories replace ad-hoc demo pages and become the canonical reference for how a component looks and behaves in every edge case.

Args-Driven Composition

Use args to decouple data from rendering. This enables the Controls panel, composition via ...Template.args, and programmatic story generation without duplicating markup.

Test Where You Develop

Play functions and @storybook/test bring Testing Library semantics into the Storybook canvas. Write interaction tests co-located with stories instead of maintaining a separate test file that renders the same component.

Setup

npx storybook@latest init
npm install -D @storybook/test @storybook/addon-a11y
// .storybook/main.ts
import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
  stories: ["../src/**/*.stories.@(ts|tsx)"],
  addons: [
    "@storybook/addon-essentials",
    "@storybook/addon-a11y",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react-vite",
};
export default config;

Key Patterns

Do: Use CSF3 with a meta default export

import type { Meta, StoryObj } from "@storybook/react";
import { Button } from "./Button";

const meta: Meta<typeof Button> = {
  component: Button,
  argTypes: { onClick: { action: "clicked" } },
};
export default meta;
type Story = StoryObj<typeof Button>;

export const Primary: Story = { args: { variant: "primary", label: "Save" } };

Not: Use the legacy storiesOf API

// Deprecated -- no type safety, no args, no play functions
storiesOf("Button", module).add("Primary", () => <Button variant="primary" />);

Do: Co-locate play functions with the story

import { expect, userEvent, within } from "@storybook/test";

export const SubmitForm: Story = {
  args: { defaultEmail: "" },
  play: async ({ canvasElement }) => {
    const canvas = within(canvasElement);
    await userEvent.type(canvas.getByRole("textbox"), "a@b.com");
    await userEvent.click(canvas.getByRole("button", { name: /submit/i }));
    await expect(canvas.getByText("Success")).toBeInTheDocument();
  },
};

Common Patterns

Args composition across stories

export const Default: Story = { args: { size: "md", disabled: false } };

export const Small: Story = { args: { ...Default.args, size: "sm" } };

export const Disabled: Story = { args: { ...Default.args, disabled: true } };

Decorators for layout and providers

const meta: Meta<typeof Card> = {
  component: Card,
  decorators: [
    (Story) => (
      <div style={{ padding: "2rem", maxWidth: 400 }}>
        <ThemeProvider theme="light">
          <Story />
        </ThemeProvider>
      </div>
    ),
  ],
};

Loaders for async data

export const WithUser: Story = {
  loaders: [
    async () => ({
      user: await fetch("/api/user/1").then((r) => r.json()),
    }),
  ],
  render: (args, { loaded: { user } }) => <Profile {...args} user={user} />,
};

Auto-generated docs page

const meta: Meta<typeof Alert> = {
  component: Alert,
  tags: ["autodocs"],
  parameters: {
    docs: {
      description: {
        component: "Displays contextual feedback messages.",
      },
    },
  },
};

Accessibility testing addon

export const HighContrast: Story = {
  args: { variant: "warning" },
  parameters: {
    a11y: {
      config: { rules: [{ id: "color-contrast", options: { noScroll: true } }] },
    },
  },
};

Anti-Patterns

  • One mega-story with conditional rendering -- split distinct states into separate named exports so the sidebar and test runner can address them individually.
  • Mocking at the network layer inside stories -- use msw via @storybook/addon-msw or loaders; avoid raw jest.fn() in story files.
  • Skipping argTypes for event handlers -- without action() bindings, click events are silent in the Actions panel, hiding interaction feedback.
  • Hard-coded wrapper widths in every story -- use decorators at the meta level or global decorators in preview.ts to set consistent layout.

When to Use

  • Building a shared component library that multiple teams consume.
  • Developing complex form or wizard components that have many visual states.
  • Running interaction tests in a real browser without a full application shell.
  • Generating visual regression snapshots via Chromatic or Percy.
  • Creating living documentation that stays in sync with code automatically.

Install this skill directly: skilldb add design-tool-services-skills

Get CLI access →