This guide teaches you how to set up a fully documented, interactive component library using Storybook 8 and React — from zero to a shareable, auto-documented UI system your team can actually use. The full setup takes roughly two to three hours, and the result is a living style guide that stays in sync with your codebase as of 2026.
What You'll Build
- A working Storybook 8 instance running inside a React or Next.js 15 project
- Documented, interactive components with typed props, controls, and accessibility annotations
- An automated component test harness using Storybook's built-in test runner (Vitest integration)
- A static Storybook export you can deploy to Vercel, Netlify, or Chromatic for team review
- A repeatable workflow that keeps docs in sync with your design system automatically
Prerequisites
- Node.js 20+ and pnpm 9 (or npm 10) installed
- An existing React 18+ or Next.js 15 project, or a fresh Vite + React scaffold
- Basic familiarity with TypeScript and JSX
- A Figma design system or at least a set of UI components to document
Step 1: Initialise Storybook 8 in Your Project
Storybook 8, released in early 2024 and stable through 2026, ships with a framework-aware CLI that auto-detects React, Next.js, and Vite. Run the init command from your project root.
pnpm dlx storybook@latest init
The CLI detects your framework and installs the correct renderer. For a Next.js 15 project it installs @storybook/nextjs. For a plain Vite + React project it installs @storybook/react-vite. Accept all prompts.
After init completes, start the dev server.
pnpm storybook
Storybook opens at http://localhost:6006 with three example stories already in place.
Common pitfall: If you see a peer dependency conflict with React 19, add --legacy-peer-deps to the npm install command or use pnpm's overrides field in package.json to pin the renderer version.
Step 2: Configure Storybook for Your Project Structure
Open .storybook/main.ts. This is the central config file. Update the stories glob to match where your components live.
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-a11y',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
The addon-a11y addon runs axe-core accessibility checks on every story automatically. This is non-negotiable for teams serving users across Australia, Singapore, Canada, and the US, where WCAG 2.2 compliance is increasingly a legal baseline.
The autodocs: 'tag' setting generates a documentation page for every component tagged with autodocs in its story file.
Step 3: Write Your First Component Story
Create a Button component and its story file side by side inside src/components/Button/.
// src/components/Button/Button.tsx
import React from 'react';
export interface ButtonProps {
label: string;
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
disabled?: boolean;
onClick?: () => void;
}
export function Button({
label,
variant = 'primary',
size = 'md',
disabled = false,
onClick,
}: ButtonProps) {
return (
);
}
// src/components/Button/Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'ghost'],
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
},
},
};
export default meta;
type Story = StoryObj;
export const Primary: Story = {
args: {
label: 'Click me',
variant: 'primary',
},
};
export const Disabled: Story = {
args: {
label: 'Not available',
disabled: true,
},
};
The argTypes block powers the Controls panel in Storybook's sidebar. Anyone on the team — including non-developers — can tweak props live in the browser without touching code.
Why does the tags: ['autodocs'] line matter?
Adding autodocs to a story's tags triggers automatic documentation generation. Storybook reads your TypeScript prop types via the react-docgen-typescript plugin and renders a live props table with no extra configuration.
Step 4: Add Interaction Testing to Stories
Storybook 8 integrates directly with Vitest for component interaction tests. This replaces the older @storybook/addon-interactions play-function approach with a faster, Vitest-native runner.
Install the test dependencies.
pnpm add -D @storybook/test @storybook/addon-vitest vitest @vitest/browser playwright
Create a vitest.config.ts at your project root.
import { defineConfig } from 'vitest/config';
import { storybookTest } from '@storybook/addon-vitest/vitest-plugin';
export default defineConfig({
plugins: [storybookTest()],
test: {
browser: {
provider: 'playwright',
enabled: true,
headless: true,
instances: [{ browser: 'chromium' }],
},
},
});
Now add a play function to your Button story to test a click interaction.
import { expect, fn, userEvent, within } from '@storybook/test';
export const Clickable: Story = {
args: {
label: 'Submit',
onClick: fn(),
},
play: async ({ args, canvasElement }) => {
const canvas = within(canvasElement);
const button = canvas.getByRole('button', { name: /submit/i });
await userEvent.click(button);
await expect(args.onClick).toHaveBeenCalledOnce();
},
};
Run all story-based tests with one command.
pnpm vitest
Pro tip: This Vitest integration, available since Storybook 8.4, cuts test setup time by roughly 60% compared to configuring Jest and Testing Library separately. It reuses your existing story definitions instead of duplicating test files.
Step 5: Document Design Tokens Inside Storybook
If your design system uses design tokens (CSS custom properties or a tokens.json from a Figma-to-code pipeline), surface them inside Storybook using MDX docs pages.
Create src/tokens/Colors.mdx.
import { Meta, ColorPalette, ColorItem } from '@storybook/blocks';
# Colour Tokens
Storybook renders a live colour swatch grid. Designers reviewing the Storybook deploy can verify tokens match Figma without opening a single code file.
Step 6: Deploy Storybook for Team Review
Build a static export of your Storybook and deploy it. You have two good options in 2026.
Option A: Deploy to Vercel or Netlify (free tier)
pnpm build-storybook
This outputs a static site to storybook-static/. Push your repository to GitHub and connect it to Vercel or Netlify. Point the build command to pnpm build-storybook and the output directory to storybook-static. Every push to main triggers a fresh deploy automatically.
Option B: Publish to Chromatic (purpose-built for Storybook)
Chromatic, built by the Storybook team, adds visual regression testing on top of the static deploy. It snapshots every story on every PR and flags pixel-level differences.
pnpm add -D chromatic
pnpm chromatic --project-token=YOUR_PROJECT_TOKEN
Chromatic's free tier allows 5,000 snapshots per month, which covers most SMB component libraries comfortably.
At Lenka Studio, we typically recommend Chromatic for client projects with active design iteration because it catches visual regressions before they reach staging — saving hours of manual QA per sprint.
Step 7: Enforce Story Coverage with a GitHub Actions Workflow
Make Storybook tests part of your CI pipeline so no component ships without a story.




