Component-Driven Development war noch nie so produktiv wie heute. Storybook 8 liefert einen
komplett neu geschriebenen Vite-Builder, verbesserte Controls, nativen Interaction-Test-Support
und eine enge Chromatic-Integration. Mit Claude Code als KI-Pair-Programmer
generierst du Stories, Docs und Interaction-Tests in Minuten statt Stunden. In diesem Beitrag
gehen wir jeden wichtigen Bereich Schritt fuer Schritt durch — mit echten Code-Snippets
und konkreten Claude-Prompts.
1. Setup Storybook 8
Storybook 8 verwendet standardmaessig den Vite-Builder, der Cold-Starts
von unter 3 Sekunden ermoeglicht. Die offizielle storybook init-CLI erkennt
dein Framework automatisch und konfiguriert alles.
01
Init ausfuehren
npx storybook@latest init — erkennt React/Next.js und installiert alle Pakete.
02
Konfiguration pruefen
main.ts und preview.ts im .storybook/-Ordner anpassen.
03
Dev starten
npm run storybook — Browser oeffnet sich automatisch auf Port 6006.
04
Claude einbinden
Claude Code liest deine Komponenten und generiert passende Stories sofort.
# In einem bestehenden React/Next.js-Projekt
npx storybook@latest init
# Storybook starten
npm run storybook
# Storybook bauen (statische Ausgabe fuer Deployment)
npm run build-storybook
main.ts — Vite-Builder konfigurieren
Storybook 8 nutzt @storybook/react-vite als Standard-Framework-Paket.
Die Konfigurationsdatei .storybook/main.ts steuert, welche Stories geladen
werden, welche Addons aktiv sind und welche Builder-Optionen gelten.
// .storybook/main.ts
import type { StorybookConfig } from '@storybook/react-vite';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-essentials', // Controls, Actions, Docs, Viewport
'@storybook/addon-interactions', // Interaction-Tests (play-Funktion)
'@storybook/addon-a11y', // Accessibility-Checks
'@chromatic-com/storybook', // Chromatic Visual Tests
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag', // Docs-Seiten auto-generieren wenn Tag gesetzt
},
viteFinalConfig: async (config) => {
// Vite-Konfiguration hier erweitern (z.B. Path-Aliases)
return config;
},
};
export default config;
preview.ts — Globale Dekoratoren und Parameter
preview.ts ist der zentrale Ort fuer globale Decorator-Registrierung,
Standard-Parameter und Theme-Integration. Hier bindest du deinen
Design-System-Provider ein.
// .storybook/preview.ts
import type { Preview } from '@storybook/react';
import '../src/styles/globals.css'; // Globale CSS-Datei einbinden
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /background|color/i,
date: /Date$/,
},
},
layout: 'centered', // Stories in der Mitte rendern
backgrounds: {
default: 'light',
values: [
{ name: 'light', value: '#ffffff' },
{ name: 'dark', value: '#0f172a' },
],
},
},
decorators: [
// Globaler Decorator: Theme-Provider wrappen
(Story) => (
<ThemeProvider theme={defaultTheme}>
<Story />
</ThemeProvider>
),
],
};
export default preview;
Claude-Prompt fuer automatisches Setup
"Lies meine package.json und erstelle .storybook/main.ts und .storybook/preview.ts fuer Storybook 8 mit React und Vite. Binde meinen ThemeProvider aus src/providers/ThemeProvider.tsx global ein."
2. Stories schreiben
Storybook 8 setzt vollstaendig auf CSF3: Jede Story ist ein benanntes
Export-Objekt vom Typ StoryObj. Das Meta-Objekt definiert
die Komponente, Standard-Args und ArgTypes. Claude Code generiert CSF3-Stories
direkt aus TypeScript-Komponenten.
Einfache Button-Story
// src/components/Button/Button.stories.ts
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
// Meta: Konfiguration fuer alle Stories dieser Datei
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
tags: ['autodocs'], // Docs-Seite automatisch generieren
args: {
label: 'Click me',
disabled: false,
},
};
export default meta;
type Story = StoryObj<typeof Button>;
// Story: Primary Button
export const Primary: Story = {
args: {
variant: 'primary',
label: 'Primary Button',
},
};
// Story: Secondary Button
export const Secondary: Story = {
args: {
variant: 'secondary',
label: 'Secondary Button',
},
};
// Story: Disabled State
export const Disabled: Story = {
args: {
disabled: true,
label: 'Nicht verfuegbar',
},
};
Args und ArgTypes
Args sind die "Inputs" einer Story. ArgTypes steuern, wie Args im Controls-Panel
dargestellt werden: als Dropdown, Color-Picker, Boolean-Toggle oder Text-Input.
Claude Code erzeugt ArgTypes automatisch aus TypeScript-Props.
// ArgTypes-Beispiel fuer ein komplexes Formularfeld
const meta: Meta<typeof InputField> = {
title: 'Forms/InputField',
component: InputField,
argTypes: {
// Enum-Prop als Dropdown im Controls-Panel
size: {
control: 'select',
options: ['sm', 'md', 'lg'],
description: 'Groesse des Eingabefeldes',
table: { defaultValue: { summary: 'md' } },
},
// Farbe als Color-Picker
borderColor: {
control: 'color',
description: 'Rahmenfarbe des Inputs',
},
// Callback als Action (wird im Actions-Panel geloggt)
onChange: {
action: 'changed',
description: 'Wird beim Aendern des Wertes aufgerufen',
},
// Boolean als Radio-Button
required: {
control: 'boolean',
},
// Number als Range-Slider
maxLength: {
control: { type: 'range', min: 1, max: 500, step: 1 },
},
},
};
Story mit play-Funktion (Kurzueberblick)
Die play-Funktion erlaubt es, nach dem Rendern einer Story automatisch
Benutzerinteraktionen zu simulieren. Details dazu in Abschnitt 5.
export const FilledForm: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Formular ausfullen und absenden
await userEvent.type(await canvas.findByLabelText('Email'), 'test@example.com');
await userEvent.click(canvas.getByRole('button', { name: /absenden/i }));
},
};
Claude-Prompt fuer Story-Generierung
"Lies src/components/Card/Card.tsx und generiere eine vollstaendige CSF3-Stories-Datei mit allen relevanten Zustaenden: Default, Loading, Error, Empty State und mit Bild. Nutze StoryObj-Typen und argTypes."
3. Controls und Actions
Controls ermoeglichen es, Props einer Komponente direkt im Browser zu aendern
ohne Code zu schreiben. Actions loggen Event-Callbacks im Actions-Panel.
Storybook 8 fuehrt fn() aus @storybook/test ein,
das automatisch mit dem Interaction-Test-Framework integriert ist.
fn() statt action() — der neue Standard in Storybook 8
In Storybook 8 ersetzt fn() die alte action()-Funktion.
fn() ist ein vollwertiger Spy, der sowohl im
Actions-Panel angezeigt wird als auch in Interaction Tests verwendbar ist.
// Storybook 8: fn() fuer Actions (NEUER STANDARD)
import { fn } from '@storybook/test';
import type { Meta, StoryObj } from '@storybook/react';
import { Modal } from './Modal';
const meta: Meta<typeof Modal> = {
title: 'Overlays/Modal',
component: Modal,
args: {
// fn() = Spy: Im Actions-Panel sichtbar UND in play() testbar
onClose: fn(),
onConfirm: fn(),
onCancel: fn(),
},
argTypes: {
size: {
control: 'radio',
options: ['sm', 'md', 'lg', 'fullscreen'],
},
variant: {
control: 'select',
options: ['default', 'danger', 'success'],
},
title: { control: 'text' },
isOpen: { control: 'boolean' },
backdropBlur: { control: 'boolean' },
},
};
export default meta;
type Story = StoryObj<typeof Modal>;
export const Default: Story = {
args: {
isOpen: true,
title: 'Aktion bestaetigen',
size: 'md',
},
};
export const DangerModal: Story = {
args: {
isOpen: true,
title: 'Eintrag loeschen',
variant: 'danger',
size: 'sm',
},
};
Controls-Typen im Ueberblick
| Control-Typ |
Einsatz |
ArgType-Config |
| text | Beliebige Zeichenkette | control: 'text' |
| number | Zahlenwerte | control: 'number' |
| range | Zahlen per Slider | control: { type: 'range', min, max, step } |
| boolean | true/false Toggle | control: 'boolean' |
| select | Dropdown aus Optionen | control: 'select', options: [...] |
| radio | Radio-Buttons aus Optionen | control: 'radio', options: [...] |
| color | Farb-Picker (Hex/RGB) | control: 'color' |
| date | Datumsauswahl | control: 'date' |
| object | JSON-Editor fuer Objekte | control: 'object' |
| file | Datei-Upload-Control | control: { type: 'file', accept: '.png' } |
Migration von action() zu fn()
In Storybook 7 war action('clicked') aus @storybook/addon-actions ueblich. Ab Storybook 8 ist fn() aus @storybook/test der Standard. Der alte Import funktioniert noch, aber fn() ist der einzige Weg, Actions auch in Interaction Tests per expect(args.onClose).toHaveBeenCalled() zu pruefen.
Claude-Prompt fuer Controls-Optimierung
"Analysiere src/components/DataTable/DataTable.tsx und erstelle argTypes fuer alle Props. Verwende passende Control-Typen: Enums als select, Booleans als boolean, Numbers mit sinnvollen min/max-Werten. Verwende fn() fuer alle Callbacks."
4. Docs
Storybook 8 generiert automatisch Docs-Seiten aus JSDoc-Kommentaren, TypeScript-Typen
und ArgTypes. Fuer individuelle Texte und Beispiele nutzt du MDX-Dateien. Claude Code
kann beides aus vorhandenen Komponenten erzeugen.
Autodocs per Tag aktivieren
Sobald du in deiner Meta-Konfiguration tags: ['autodocs'] setzt,
generiert Storybook automatisch eine Docs-Seite mit Props-Tabelle, Stories-Vorschau
und Code-Beispielen.
// Autodocs: nur Tag setzen
const meta: Meta<typeof Badge> = {
title: 'Components/Badge',
component: Badge,
tags: ['autodocs'], // Das reicht! Storybook generiert die Docs-Seite.
};
// Alternativ: Docs fuer ALLE Stories in main.ts global aktivieren
// docs: { autodocs: 'tag' } → nur wenn Tag gesetzt
// docs: { autodocs: true } → fuer alle Stories
JSDoc-Kommentare fuer bessere Docs
Storybook liest JSDoc-Kommentare direkt aus deinen TypeScript-Typen und zeigt
sie in der Props-Tabelle an. Claude Code schreibt diese Kommentare auf Anfrage
fuer alle Props einer Komponente.
// src/components/Avatar/Avatar.tsx
interface AvatarProps {
/** URL des Profilbildes. Wird 'fallback' angezeigt wenn nicht vorhanden. */
src?: string;
/** Alt-Text fuer das Bild (fuer Screenreader). */
alt: string;
/** Groesse des Avatars in Pixeln. Standard: 40. */
size?: 24 | 32 | 40 | 48 | 64 | 80;
/**
* Initialen des Nutzers als Fallback wenn kein Bild vorhanden.
* @example 'AB' fuer 'Anna Braun'
*/
initials?: string;
/** Zeigt einen Onlinestatus-Indikator an. */
showStatus?: boolean;
/** Statusfarbe des Indikators. */
status?: 'online' | 'away' | 'busy' | 'offline';
}
MDX-Dokumentation fuer komplexe Komponenten
Fuer Komponenten, die mehr als eine automatisch generierte Props-Tabelle benoetigen,
erstellst du eine .mdx-Datei. MDX kombiniert Markdown-Text mit
eingebetteten Storybook-Komponenten wie <Canvas> und <Controls>.
{/* src/components/Tooltip/Tooltip.mdx */}
import { Meta, Canvas, Controls, Story } from '@storybook/blocks';
import * as TooltipStories from './Tooltip.stories';
<Meta of={TooltipStories} />
# Tooltip
Der `Tooltip`-Komponente zeigt kontextuelle Hilfetexte beim Hovern ueber ein Element.
Er unterstuetzt vier Positionen und kann mit beliebigem JSX als Inhalt genutzt werden.
## Verwendung
<Canvas of={TooltipStories.Default} />
<Controls of={TooltipStories.Default} />
## Alle Positionen
<Canvas of={TooltipStories.AllPositions} />
## Barrierefreiheit
Tooltips werden per `role="tooltip"` und `aria-describedby` korrekt ausgezeichnet.
Wichtig: Der ausloesende Button muss fokussierbar sein (`tabIndex={0}`).
<Story of={TooltipStories.WithKeyboardFocus} />
Claude-Prompt fuer MDX-Docs
"Erstelle eine MDX-Dokumentationsdatei fuer src/components/Dropdown/Dropdown.tsx. Beschreibe Verwendungszweck, Accessibility-Hinweise, Do/Don'ts und binde alle vorhandenen Stories per Canvas-Block ein."
5. Interaction Tests
Storybook 8 integriert Vitest als Test-Runner direkt.
Die play-Funktion einer Story ist gleichzeitig ein Interaction-Test:
Sie laeuft im Browser, simuliert echte Nutzereingaben und asserted Ergebnisse.
Kein separater Test-Runner noetig.
Grundstruktur eines Interaction-Tests
// src/components/LoginForm/LoginForm.stories.tsx
import { within, userEvent, expect, fn } from '@storybook/test';
import type { Meta, StoryObj } from '@storybook/react';
import { LoginForm } from './LoginForm';
const meta: Meta<typeof LoginForm> = {
title: 'Auth/LoginForm',
component: LoginForm,
args: {
onLogin: fn(),
onForgotPassword: fn(),
},
};
export default meta;
type Story = StoryObj<typeof LoginForm>;
// Story mit vollstaendigem Interaction-Test
export const SuccessfulLogin: Story = {
play: async ({ canvasElement, args }) => {
const canvas = within(canvasElement);
// Email-Feld ausfullen
const emailInput = canvas.getByLabelText(/email/i);
await userEvent.clear(emailInput);
await userEvent.type(emailInput, 'user@example.com');
// Passwort-Feld ausfullen
const passwordInput = canvas.getByLabelText(/passwort/i);
await userEvent.type(passwordInput, 'SecureP@ss123');
// Absenden-Button klicken
await userEvent.click(canvas.getByRole('button', { name: /anmelden/i }));
// Assert: onLogin wurde mit korrekten Werten aufgerufen
await expect(args.onLogin).toHaveBeenCalledWith({
email: 'user@example.com',
password: 'SecureP@ss123',
});
// Assert: Erfolgsanzeige sichtbar
await expect(canvas.getByText(/anmeldung erfolgreich/i)).toBeInTheDocument();
},
};
// Story: Validierungsfehler-Zustand testen
export const ValidationErrors: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
// Formular ohne Eingaben absenden
await userEvent.click(canvas.getByRole('button', { name: /anmelden/i }));
// Assert: Fehlermeldungen erscheinen
await expect(canvas.getByText(/email ist erforderlich/i)).toBeVisible();
await expect(canvas.getByText(/passwort ist erforderlich/i)).toBeVisible();
},
};
Interaction-Tests im CI ausfuehren
Mit dem Storybook-Test-Runner koennen alle play-Funktionen als automatisierte
Tests in der CI-Pipeline laufen. Installation und Konfiguration sind minimal.
# Test-Runner installieren
npm install --save-dev @storybook/test-runner
# package.json Script hinzufuegen
"test-storybook": "test-storybook"
# Storybook im Hintergrund starten, dann Tests ausfuehren
npx concurrently -k -s first -n "SB,TEST" \
"npm run storybook -- --ci" \
"npx wait-on tcp:6006 && npm run test-storybook"
# Alternativ: Mit bereits laufendem Storybook
npm run test-storybook -- --url http://localhost:6006
Claude-Prompt fuer Interaction-Tests
"Schreibe Interaction-Tests (play-Funktionen) fuer alle Stories in src/components/SearchBar/SearchBar.stories.tsx. Teste: leere Eingabe zeigt Fehler, gueltige Suche ruft onSearch auf, Escape-Taste leert das Feld, Ergebnisliste erscheint nach Tippen."
6. Chromatic Visual Regression
Chromatic ist der offiziell empfohlene Visual-Test-Dienst fuer Storybook.
Jede Story wird als Screenshot gespeichert. Bei jedem Commit vergleicht
Chromatic neue Screenshots mit den gespeicherten Baselines und meldet
visuelle Veraenderungen. Claude Code hilft dir, Chromatic korrekt
zu konfigurieren und falsche Positiv-Ergebnisse zu minimieren.
Chromatic installieren und konfigurieren
# Chromatic-Paket installieren
npm install --save-dev chromatic
# Storybook-Addon fuer Chromatic-Integration
npm install --save-dev @chromatic-com/storybook
# Einmalig: Projekt bei Chromatic erstellen und ersten Upload
npx chromatic --project-token=YOUR_CHROMATIC_PROJECT_TOKEN
GitHub Actions CI-Integration
# .github/workflows/chromatic.yml
name: 'Chromatic'
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
chromatic:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Komplette Git-History fuer TurboSnap
- name: Install dependencies
run: npm ci
- name: Publish to Chromatic
uses: chromaui/action@latest
with:
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
exitZeroOnChanges: true # CI nicht blockieren bei visuellen Aenderungen
autoAcceptChanges: 'main' # main-Branch automatisch akzeptieren
onlyChanged: true # TurboSnap: nur geaenderte Stories testen
Diff-Threshold und Story-Parameter
Fuer Komponenten mit animierten Inhalten oder dynamischen Werten (Timestamps, Zufallsdaten)
kannst du per Story-Parameter die Chromatic-Empfindlichkeit anpassen oder
spezifische Stories vom Visual-Test ausschliessen.
// Chromatic-Parameter pro Story konfigurieren
export const AnimatedLoader: Story = {
parameters: {
chromatic: {
// Pause Animation vor Screenshot
pauseAnimationAtEnd: true,
// Hoeherer Diff-Threshold fuer Pixel-Toleranz (0-1)
diffThreshold: 0.3,
// Verschiedene Viewport-Breiten fuer Responsive-Tests
viewports: [375, 768, 1280],
},
},
};
export const RealtimeClock: Story = {
parameters: {
chromatic: {
disableSnapshot: true, // Story komplett vom Visual-Test ausschliessen
},
},
};
// Globale Chromatic-Einstellungen in preview.ts
export const parameters = {
chromatic: {
viewports: [320, 768, 1200], // Standard-Viewports fuer alle Stories
diffThreshold: 0.2, // Globale Pixel-Toleranz
delay: 300, // Warte 300ms vor Screenshot
},
};
Baseline-Management mit Claude Code
Wenn sich dein Design-System aendert, muessen viele Baselines gleichzeitig aktualisiert
werden. Claude Code hilft dir, den Chromatic-Workflow zu automatisieren.
# Neue Baselines nach Design-System-Update akzeptieren
npx chromatic --project-token=YOUR_TOKEN --auto-accept-changes
# Nur bestimmte Stories testen (nach Komponenten-Name)
npx chromatic --project-token=YOUR_TOKEN \
--only-story-names "Components/Button*"
# Branch-spezifische Baselines (fuer Feature-Branches)
npx chromatic --project-token=YOUR_TOKEN \
--branch-name "feat/new-design"
Claude-Prompt fuer Chromatic-Konfiguration
"Analysiere alle Stories in src/components/ und identifiziere solche mit Animationen, Timestamps oder Random-Daten. Fuge fuer diese Stories passende chromatic-Parameter (disableSnapshot oder pauseAnimationAtEnd) hinzu und erstelle einen vollstaendigen GitHub Actions Workflow fuer Chromatic."
TurboSnap ist ein Chromatic-Feature, das per Git-Diff erkennt, welche
Komponenten sich geaendert haben, und nur deren Stories neu testet.
Das reduziert die CI-Kosten um typischerweise 70-90% in reifen Projekten.
Voraussetzung: fetch-depth: 0 im GitHub-Actions-Checkout.
Mit Claude Code koennen Storybook-Konfiguration, Stories, Interaction-Tests
und Chromatic-Workflow vollstaendig aus dem Quellcode einer Komponente
generiert werden — von der Props-Analyse bis zum fertigen CI-YAML.
Jetzt agentenbasiertes Development ausprobieren
Claude Code generiert Storybook-Stories, Interaction-Tests und Chromatic-Workflows
direkt aus deinen React-Komponenten. Starte kostenlos und erlebe,
wie KI-gestuetztes Component-Driven Development aussieht.
Kostenlosen Trial starten →