Story Structure Reference
Last Updated: November 23, 2025
This document defines the standard structure and patterns for Storybook story files in the Savvi Studio project.
Table of Contents
- Basic Story Structure
- Meta Configuration
- Tags System
- Lifecycle Hooks
- Story-Level Overrides
- Best Practices
Basic Story Structure
Every story file should follow this standard structure:
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentName } from './ComponentName';
const meta = {
title: 'Category/SubCategory/ComponentName',
component: ComponentName,
parameters: {
layout: 'padded', // or 'centered' | 'fullscreen'
},
tags: ['autodocs'],
} satisfies Meta<typeof ComponentName>;
export default meta;
type Story = StoryObj<typeof meta>;
// Stories
export const Default: Story = {
args: {
// component props
},
};
export const Variant: Story = {
args: {
// different props
},
};
Meta Configuration
Title Conventions
Use clear, hierarchical titles:
// ✅ Good - Clear hierarchy
title: 'Admin/Setup/TenantSetupForm'
title: 'Auth/LoginPage'
title: 'Common/Button'
title: 'Layout/Header'
// ❌ Avoid - Unclear hierarchy
title: 'TenantSetupForm'
title: 'Login'
Layout Options
parameters: {
layout: 'padded', // Default - adds padding around story
layout: 'centered', // Centers story in viewport
layout: 'fullscreen' // No padding, full viewport
}
When to use each:
padded: Most components (forms, cards, tables)centered: Small components (buttons, icons, badges)fullscreen: Page-level components (layouts, pages)
Common Parameters
const meta = {
component: MyComponent,
parameters: {
layout: 'padded',
// Control documentation
docs: {
description: {
component: 'A brief description of the component',
},
},
// Design integration
design: {
type: 'figma',
url: 'https://figma.com/...',
},
},
} satisfies Meta<typeof MyComponent>;
Tags System
Tags enable story organization, filtering, and special behaviors.
Standard Tags
const meta = {
component: Button,
tags: ['autodocs', 'stable'],
} satisfies Meta<typeof Button>;
Common tags:
autodocs- Auto-generate documentationstable- Production-ready componentexperimental- Work in progressdeprecated- Legacy component
Story-Level Tags
Override or extend component-level tags:
// Hide from dev sidebar
export const Experimental: Story = {
tags: ['experimental', '!dev'],
};
// Mark as deprecated
export const OldPattern: Story = {
tags: ['deprecated'],
};
Tag Configuration
Configure custom tags in .storybook/main.ts:
export default {
tags: {
experimental: {
title: 'Experimental',
description: 'Features under development',
defaultFilterSelection: 'exclude',
},
stable: {
title: 'Stable',
description: 'Production-ready components',
},
deprecated: {
title: 'Deprecated',
description: 'Legacy components to be removed',
defaultFilterSelection: 'exclude',
},
},
};
Lifecycle Hooks
Lifecycle hooks enable setup and teardown for stories.
Global Hooks
Configure in .storybook/preview.tsx:
import { Preview } from '@storybook/react';
import MockDate from 'mockdate';
const preview: Preview = {
async beforeEach() {
// Setup before each story
MockDate.set('2024-01-01T00:00:00Z');
localStorage.clear();
// Return cleanup function
return () => {
MockDate.reset();
localStorage.clear();
};
},
};
export default preview;
Story-Level Hooks
Override global hooks or add story-specific setup:
export const WithLocalStorage: Story = {
async beforeEach() {
// Story-specific setup
localStorage.setItem('user', JSON.stringify({ id: '123' }));
// Cleanup
return () => {
localStorage.removeItem('user');
};
},
};
Common Use Cases
Date/Time Mocking:
beforeEach() {
MockDate.set('2024-01-01T12:00:00Z');
return () => MockDate.reset();
}
localStorage/sessionStorage:
beforeEach() {
localStorage.setItem('theme', 'dark');
return () => localStorage.clear();
}
API Mocking State:
beforeEach() {
// Reset MSW handlers to defaults
return () => {
// Cleanup handlers
};
}
Story-Level Overrides
Override global settings for specific stories.
Background Override
export const OnDark: Story = {
globals: {
backgrounds: { value: 'dark' },
},
};
export const OnLight: Story = {
globals: {
backgrounds: { value: 'light' },
},
};
Theme Override
export const LightTheme: Story = {
globals: {
theme: 'light',
},
};
export const DarkTheme: Story = {
globals: {
theme: 'dark',
},
};
Viewport Override
export const Mobile: Story = {
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
},
};
export const Tablet: Story = {
parameters: {
viewport: {
defaultViewport: 'tablet',
},
},
};
Best Practices
1. Consistent Naming
// ✅ Good - Clear, descriptive names
export const Default: Story = {};
export const WithError: Story = {};
export const Loading: Story = {};
export const Disabled: Story = {};
// ❌ Avoid - Vague names
export const Story1: Story = {};
export const Test: Story = {};
export const Example: Story = {};
2. Organize Stories Logically
// ✅ Good - Grouped by state/variant
export const Default: Story = {};
export const WithData: Story = {};
export const Loading: Story = {};
export const Error: Story = {};
// States
export const Disabled: Story = {};
export const ReadOnly: Story = {};
// Variants
export const Primary: Story = {};
export const Secondary: Story = {};
3. Use Args Composition
// ✅ Good - Reuse args
const baseArgs = {
label: 'Submit',
onClick: fn(),
};
export const Primary: Story = {
args: {
...baseArgs,
variant: 'primary',
},
};
export const Secondary: Story = {
args: {
...baseArgs,
variant: 'secondary',
},
};
4. Document Complex Props
const meta = {
component: DataTable,
argTypes: {
data: {
description: 'Array of row objects to display',
table: {
type: { summary: 'Array<Record<string, unknown>>' },
},
},
onRowClick: {
description: 'Callback fired when a row is clicked',
table: {
type: { summary: '(row: T) => void' },
},
},
},
} satisfies Meta<typeof DataTable>;
5. Provide Realistic Data
// ✅ Good - Realistic mock data
export const WithUsers: Story = {
args: {
users: [
{ id: '1', name: 'Alice Johnson', email: 'alice@example.com' },
{ id: '2', name: 'Bob Smith', email: 'bob@example.com' },
],
},
};
// ❌ Avoid - Minimal/unrealistic data
export const WithUsers: Story = {
args: {
users: [{ id: '1', name: 'A' }],
},
};
Related Documentation
- Testing Patterns - Testing Library and interaction patterns
- MSW Handlers - API mocking patterns
- Decorators - Story decorator patterns
- Helpers - Reusable story utilities
For task-specific implementation details, see the Storybook integration task files in docs/storybook-integration/.