with Storybook
Storybook and Tailwind CSS are a natural combination: Tailwind provides the design system foundation through utility classes, Storybook makes it visible, testable and documented for the whole team. The result is a living component catalog that stays in sync with the code.
Table of Contents
- 1. Why Storybook for Tailwind CSS projects?
- 2. Setting up Storybook with Tailwind CSS
- 3. Writing the first Tailwind CSS story
- 4. Storybook controls for Tailwind variants
- 5. Design tokens: making Tailwind colors available in Storybook
- 6. Testing dark mode in Storybook
- 7. Accessibility testing directly in Storybook
- 8. Autodocs and MDX for complete documentation
- 9. Comparing Storybook strategies for Tailwind
- 10. Summary
- 11. FAQ
1. Why Storybook for Tailwind CSS projects?
In a Tailwind CSS project, UI components often grow faster than their documentation. Button variants, badge colors, card layouts, every new component brings new combinations of Tailwind classes. Without living component documentation, developers and designers quickly lose track of which variants exist, which classes they use and how they look in different states. Tailwind CSS Storybook solves this problem: every component is documented in isolation, shown in all relevant states and made accessible to the whole team.
Storybook is framework-agnostic and supports React, Vue, Angular, Svelte and plain HTML. In Tailwind CSS projects the approach is the same regardless of the framework: the component renders HTML with Tailwind classes, Storybook displays it in isolation, and Storybook controls make it possible to change Tailwind classes or component props interactively. Designers can check directly in the browser whether the colors are correct. QA teams can test accessibility. New developers find all components in one place. The Tailwind CSS Storybook becomes the single source of truth for the design system.
2. Setting up Storybook with Tailwind CSS
The Storybook setup for a Tailwind CSS project starts with installing Storybook into the existing project. npx storybook@latest init automatically detects the framework in use (React, Vue, etc.) and configures the basic Storybook files. The next step is the Tailwind integration: the project's main CSS file, which contains the @tailwind base, @tailwind components and @tailwind utilities import, must be imported in the Storybook preview configuration. This happens in .storybook/preview.js or preview.ts.
If the project uses Vite as the build tool, .storybook/main.js must also reference the Vite config file so that the Tailwind CSS PostCSS pipeline is active in Storybook as well. In Webpack projects, the PostCSS plugin is enabled in the Storybook Webpack configuration. In both cases the goal is the same: Storybook should produce the same CSS output as the actual application. A common mistake in Tailwind CSS Storybook setups: the content configuration in tailwind.config.js does not include the story files, so Tailwind does not find the classes used in stories and removes them during the build.
// .storybook/main.js, Storybook + Tailwind CSS + Vite setup
import { mergeConfig } from 'vite';
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
stories: [
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|mjs|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-a11y', // Accessibility testing
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
viteFinal: async (config) => {
// Merge Tailwind CSS PostCSS config from the main Vite config
return mergeConfig(config, {
css: {
postcss: './postcss.config.js',
},
});
},
};
export default config;
// .storybook/preview.js, Import Tailwind CSS and global styles
import '../src/styles/globals.css'; // Contains @tailwind base/components/utilities
/** @type { import('@storybook/react').Preview } */
const preview = {
parameters: {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
// Default background for stories, white matches most Tailwind components
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#ffffff' },
{ name: 'gray', value: '#f8fafc' },
{ name: 'dark', value: '#0f172a' },
],
},
},
};
export default preview;
3. Writing the first Tailwind CSS story
A story in Storybook is a function that renders a component in a particular state. For Tailwind CSS components this means: the story renders the component with specific Tailwind classes or props that control Tailwind classes internally. The Component Story Format (CSF) is the standard form: a default export object defines the component type and metadata, individual named exports define the stories. For a simple button component there are separate stories for Primary, Secondary, Destructive, Disabled and Loading.
The most important design decision in Tailwind CSS Storybook stories: are the Tailwind classes passed as props (e.g. variant="primary", which maps internally to specific classes), or are the classes passed directly as args? The first approach is cleaner and makes the component API explicit. The second approach is more flexible, but it couples the story directly to Tailwind classes and makes future changes harder. For reusable design system components, the variant-prop pattern is the recommended choice because it separates the Tailwind implementation from the component API.
// src/components/Button/Button.stories.tsx, Tailwind CSS + Storybook
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta: Meta<typeof Button> = {
title: 'Design System/Button',
component: Button,
parameters: {
layout: 'centered',
docs: {
description: {
component: 'Primary UI action button. Uses Tailwind CSS utility classes internally.',
},
},
},
// Auto-generate controls for all props
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'destructive', 'ghost'],
description: 'Visual style of the button',
},
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
description: 'Button size, maps to Tailwind padding and text classes',
},
disabled: { control: 'boolean' },
loading: { control: 'boolean' },
},
};
export default meta;
type Story = StoryObj<typeof meta>;
// Default story, primary, medium size
export const Primary: Story = {
args: { variant: 'primary', size: 'md', children: 'Request now' },
};
export const Secondary: Story = {
args: { variant: 'secondary', size: 'md', children: 'Learn more' },
};
export const Destructive: Story = {
args: { variant: 'destructive', size: 'md', children: 'Delete' },
};
export const AllVariants: Story = {
render: () => (
<div className="flex flex-wrap gap-4 items-center">
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="ghost">Ghost</Button>
</div>
),
};
4. Storybook controls for Tailwind variants
Storybook controls make the biggest difference in the Tailwind CSS Storybook experience: they allow props to be changed interactively in the Storybook UI without writing code. For Tailwind CSS components that control variants through props, controls work out of the box: a select control for variant, a boolean control for disabled, a range control for size steps. That makes it possible to explore every state of a component without separate stories.
For advanced use cases, for example when Tailwind classes are passed directly as a string prop, the control can be configured as free text input. That is useful for spacing overrides or color adjustments. A dedicated addon named storybook-tailwind-controls (or similar community addons) can render Tailwind color palettes directly as color pickers in controls. In most cases, however, the built-in controls addon is fully sufficient once the component API is clearly structured and Tailwind classes are mapped internally through props.
5. Design tokens: making Tailwind colors available in Storybook
A central feature of a design system is documenting the design decisions themselves, meaning the colors, spacing, font sizes and other tokens. With Tailwind CSS Storybook, tailwind.config.js can be imported directly into Storybook to display a living color palette, spacing documentation and type scale. To do this, the Tailwind configuration is imported in a separate MDX file or story and rendered in a formatted overview.
The Storybook addon @storybook/addon-docs contains the ColorPalette component, which renders color swatches with name and hex value. By converting the Tailwind color palette programmatically into this format, an always-current color documentation emerges that never goes stale. When the color scheme in tailwind.config.js is changed, the Storybook documentation updates automatically on the next build. That is the promise of a living design system: documentation and implementation are never out of sync.
6. Testing dark mode in Storybook
If the Tailwind CSS project supports dark mode via dark: classes, Storybook needs a way to switch between light and dark mode. The addon storybook-dark-mode adds a toggle to the Storybook toolbar and switches the CSS class dark on the <html> element. Since Tailwind CSS v3 responds to exactly this class in class-based dark mode, the toggle works immediately without further configuration.
In .storybook/preview.js, the addon is configured: which theme Storybook itself uses for light and dark mode (the Storybook UI theme), and which class is set on the canvas element. For Tailwind CSS v3 with darkMode: 'class', it is important that the class is set on the <html> element of the story canvas, not on the canvas container itself. The story should also show a dark mode background so that white text on a dark background remains correctly visible.
7. Accessibility testing directly in Storybook
The Storybook addon @storybook/addon-a11y automatically runs axe-core checks on every story and displays violations directly in the Storybook UI. For Tailwind CSS components this is particularly valuable because Tailwind itself makes no statements about accessibility, the correctness of color contrasts, ARIA attributes and keyboard navigation is entirely up to the developer. The a11y addon automatically checks contrast ratios of Tailwind colors, missing alt text, incorrect ARIA roles and other WCAG violations.
The approach for a complete Tailwind CSS Storybook accessibility setup: add the addon in main.js, create a story with a known accessibility problem (for example a button without an ARIA label), and observe how the addon reports the violation. Then fix the problem and make sure all further stories pass the a11y checks. The checks can also be integrated into a CI pipeline: npx storybook build && npx axe-core-storybook fails if a story contains a critical accessibility error. That turns accessibility into an automated gate in the development process.
8. Autodocs and MDX for complete documentation
Storybook 8 offers, with tags: ['autodocs'] in the story metadata, an automatic documentation page for every component. This page shows all stories, all props with their types and default values, and an editable description text. For Tailwind CSS components this is especially useful because it documents the prop-to-class mapping: which props control which Tailwind classes? Which variants exist? This is documentation generated directly from the TypeScript types and the story argTypes.
MDX files allow even more control: in a Button.mdx file, Markdown text can be combined with embedded stories. This makes it possible to place context, usage guidelines and code examples directly next to the interactive story preview. One section explains when to use which button variant. Another shows which Tailwind classes are used internally. A table documents all props. That is the complete component documentation that designers and developers can use together.
9. Comparing Storybook strategies for Tailwind
There are various approaches to how Tailwind CSS and Storybook can work together. The choice depends on team size, the framework and the desired level of documentation detail.
| Strategy | Effort | Documentation depth | Recommendation |
|---|---|---|---|
| CSF stories + Autodocs | Low | Automatic from types | Starting point for all projects |
| CSF + controls for Tailwind classes | Medium | Interactive, all variants | For active design system development |
| MDX + design token pages | High | Complete, for designers | For products with their own design system |
| a11y addon + CI integration | Medium | Automated | Mandatory for WCAG requirements |
| Chromatic for visual regression testing | High (external) | Screenshot diffs per story | For large teams with a stable design |
The practical entry point for an existing Tailwind CSS Storybook project: first document the most important reusable components (Button, Badge, Card, Input) with simple CSF stories and Autodocs. Then add controls for the most common variants. Add the a11y addon from the start, it costs almost nothing and finds real problems. Add MDX and design token pages once the team has grown and designers regularly work with Storybook.
Mironsoft
Design systems, Tailwind CSS and component documentation
Building a design system with Storybook?
We help you build a living Tailwind CSS design system with Storybook, from the initial configuration through stories and controls to a11y integration and CI deployment.
Storybook setup
Tailwind CSS integration, addons and CI pipeline for automatic Storybook builds
Component documentation
Stories, controls and MDX pages for all reusable Tailwind components
Design tokens
Tailwind colors, spacing and type scale as living token documentation in Storybook
10. Summary
Tailwind CSS Storybook is the combination that turns a collection of utility classes into a documented, testable design system visible to the whole team. The setup begins with importing the Tailwind CSS main file into .storybook/preview.js and the correct PostCSS configuration in main.js. CSF stories with Autodocs automatically generate documentation pages. Storybook controls make Tailwind variants interactively explorable. The a11y addon checks accessibility automatically on every story.
The long-term value lies in consistency: when every new Tailwind CSS component is documented directly in Storybook, the documentation does not rot. Designers can check components directly in the browser. QA teams can explore states without setting up tests in the application. New developers find all components in one place. And as the team grows, Storybook can be extended with MDX pages, design token documentation and visual regression tests with Chromatic, without having to change the underlying structure.
Tailwind CSS Storybook: the essentials at a glance
Basic setup
Import the Tailwind CSS main file in .storybook/preview.js. Make sure the PostCSS configuration in main.js is set up for Vite/Webpack.
Watch the safelist
Include story files (**/*.stories.{js,ts,tsx}) in the tailwind.config.js content, otherwise classes from stories are missing in the build.
Controls for variants
Configure variant props with control: 'select'. Control Tailwind classes internally through variant props, not passed directly as controls.
a11y from day one
Add @storybook/addon-a11y from the start. axe-core finds contrast and ARIA errors automatically on every story.
11. FAQ: Tailwind CSS Storybook
1How do I integrate Tailwind CSS into Storybook?
.storybook/preview.js. PostCSS configuration in main.js for Vite/Webpack. Add story paths to tailwind.config.js content.2Why are Tailwind classes missing in Storybook?
tailwind.config.js content, so Tailwind does not scan them. Add ./src/**/*.stories.{js,ts,tsx} to content.3Document Tailwind variants with controls?
control: 'select'. Map variants internally to Tailwind classes. Controls show all states without separate stories.4Test dark mode in Storybook?
storybook-dark-mode addon sets the class dark on the canvas html element. With darkMode: 'class' in tailwind.config.js, it works immediately.5Accessibility tests in Storybook?
@storybook/addon-a11y runs axe-core on every story. Contrast, ARIA, labels, checked automatically, visible directly in the UI.6What is Autodocs?
tags: ['autodocs'] in metadata activates automatic documentation pages from TypeScript types and argTypes, no manual MDX needed.7Design tokens in Storybook?
tailwind.config.js in MDX, use ColorPalette from Addon-Docs. Automatically up to date when config changes.8Which Storybook version to recommend?
@storybook/react-vite, for Vue: @storybook/vue3-vite.9Plain HTML with Tailwind in Storybook?
@storybook/html-vite framework. Stories return HTML strings. Full Tailwind CSS support without React or Vue.10Integrate Storybook into CI/CD?
npx storybook build for a static build. @storybook/test-runner for Playwright tests. Chromatic for visual regression testing as SaaS.