From storybook
Configures Storybook via main.ts and preview.ts files, addons like essentials and a11y, builders, story patterns, autodocs, and React-Vite frameworks. Use for project setup or tweaks.
npx claudepluginhub thebushidocollective/han --plugin storybookThis skill is limited to using the following tools:
Configure Storybook for optimal development experience with the right addons, builders, and framework integrations.
Provides Storybook 10 testing patterns with Vitest integration, CSF3 typesafe factories, play() interactions, Chromatic TurboSnap visual regression, module automocking, a11y tests, and autodocs. Use for component stories, visual testing, CI pipelines, or Storybook 9 migration.
Creates or modifies Storybook stories in CSF3 format for React components, showcasing variations with TypeScript type safety and ensuring builds succeed.
Generates CSF3 Storybook stories for React/Vue components with variant coverage and state matrices. Use when creating stories or scanning for missing ones.
Share bugs, ideas, or general feedback.
Configure Storybook for optimal development experience with the right addons, builders, and framework integrations.
.storybook/main.ts is the primary configuration file:
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
.storybook/preview.ts configures how stories are rendered:
import type { Preview } from '@storybook/react';
import '../src/index.css';
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
},
globalTypes: {
theme: {
description: 'Global theme for components',
defaultValue: 'light',
toolbar: {
title: 'Theme',
icon: 'circlehollow',
items: ['light', 'dark'],
dynamicTitle: true,
},
},
},
};
export default preview;
Addons extend Storybook functionality:
Type-safe configuration prevents errors:
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {
builder: {
viteConfigPath: './vite.config.ts',
},
},
},
};
export default config;
Specify where stories are located:
const config: StorybookConfig = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|ts|tsx)',
// Include specific directories
'../components/**/*.stories.tsx',
'../features/**/*.stories.tsx',
// Exclude patterns
'!../src/**/*.test.stories.tsx',
],
};
Generate documentation automatically:
const config: StorybookConfig = {
docs: {
autodocs: 'tag', // Autodocs for stories with 'autodocs' tag
// OR
autodocs: true, // Autodocs for all stories
},
};
Customize addon behavior in preview:
import type { Preview } from '@storybook/react';
const preview: Preview = {
parameters: {
// Actions addon
actions: { argTypesRegex: '^on[A-Z].*' },
// Controls addon
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
exclude: ['className', 'style'],
},
// Viewport addon
viewport: {
viewports: {
mobile: {
name: 'Mobile',
styles: { width: '375px', height: '667px' },
},
tablet: {
name: 'Tablet',
styles: { width: '768px', height: '1024px' },
},
},
},
// Backgrounds addon
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#ffffff' },
{ name: 'dark', value: '#1a1a1a' },
],
},
},
};
Wrap all stories with providers:
import { Preview } from '@storybook/react';
import { ThemeProvider } from '../src/theme';
const preview: Preview = {
decorators: [
(Story) => (
<ThemeProvider>
<div style={{ padding: '2rem' }}>
<Story />
</div>
</ThemeProvider>
),
],
};
import type { StorybookConfig } from '@storybook/nextjs';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/nextjs',
options: {
nextConfigPath: '../next.config.js',
},
},
staticDirs: ['../public'],
typescript: {
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
},
},
};
import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';
const config: StorybookConfig = {
framework: {
name: '@storybook/react-vite',
options: {},
},
async viteFinal(config) {
return mergeConfig(config, {
resolve: {
alias: {
'@': '/src',
},
},
define: {
'process.env.STORYBOOK': JSON.stringify(true),
},
});
},
};
import type { StorybookConfig } from '@storybook/react-webpack5';
import path from 'path';
const config: StorybookConfig = {
framework: {
name: '@storybook/react-webpack5',
options: {},
},
webpackFinal: async (config) => {
config.resolve = {
...config.resolve,
alias: {
...config.resolve?.alias,
'@': path.resolve(__dirname, '../src'),
},
};
return config;
},
};
import type { Preview } from '@storybook/react';
const preview: Preview = {
parameters: {
a11y: {
config: {
rules: [
{
id: 'color-contrast',
enabled: true,
},
{
id: 'aria-required-attr',
enabled: true,
},
],
},
options: {
runOnly: {
type: 'tag',
values: ['wcag2a', 'wcag2aa'],
},
},
},
},
};
import { Preview } from '@storybook/react';
import { useDarkMode } from 'storybook-dark-mode';
const preview: Preview = {
decorators: [
(Story) => {
const isDark = useDarkMode();
return (
<ThemeProvider theme={isDark ? darkTheme : lightTheme}>
<Story />
</ThemeProvider>
);
},
],
};
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
addons: [
'@storybook/addon-coverage',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
};
// In .storybook/test-runner.ts
import type { TestRunnerConfig } from '@storybook/test-runner';
const config: TestRunnerConfig = {
async postRender(page, context) {
// Add coverage collection
await page.coverage.startJSCoverage();
},
};
export default config;
// .storybook/main.react.ts
const config: StorybookConfig = {
stories: ['../src/react/**/*.stories.tsx'],
framework: '@storybook/react-vite',
};
// .storybook/main.vue.ts
const config: StorybookConfig = {
stories: ['../src/vue/**/*.stories.ts'],
framework: '@storybook/vue3-vite',
};
// .storybook/addons/custom-addon/register.tsx
import { addons, types } from '@storybook/manager-api';
import { AddonPanel } from '@storybook/components';
import React from 'react';
addons.register('custom-addon', () => {
addons.add('custom-addon/panel', {
type: types.PANEL,
title: 'Custom Panel',
render: ({ active, key }) => (
<AddonPanel active={active} key={key}>
<div>Custom addon content</div>
</AddonPanel>
),
});
});
// .storybook/main.ts
const config: StorybookConfig = {
addons: ['./addons/custom-addon/register'],
};
// .storybook/manager.ts
import { addons } from '@storybook/manager-api';
import { themes } from '@storybook/theming';
addons.setConfig({
theme: themes.dark,
panelPosition: 'right',
showPanel: true,
selectedPanel: 'storybook/actions/panel',
initialActive: 'sidebar',
sidebar: {
showRoots: true,
collapsedRoots: ['other'],
},
});
// Bad - No type safety
const config = {
framework: '@storybook/react-vite',
};
// Good - Type-safe
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
framework: {
name: '@storybook/react-vite',
options: {},
},
};
// Bad
const config: StorybookConfig = {
stories: [
'/Users/username/project/src/**/*.stories.tsx',
],
};
// Good
const config: StorybookConfig = {
stories: [
'../src/**/*.stories.tsx',
],
};
// Bad - Too many addons slow down Storybook
const config: StorybookConfig = {
addons: [
'@storybook/addon-essentials',
'@storybook/addon-actions', // Included in essentials
'@storybook/addon-controls', // Included in essentials
'@storybook/addon-backgrounds', // Included in essentials
],
};
// Good - Just essentials covers most needs
const config: StorybookConfig = {
addons: [
'@storybook/addon-essentials',
'@storybook/addon-a11y', // Additional specialized addon
],
};