Storybook Guidelines¶
This document provides comprehensive guidelines for creating well-structured, consistent, and helpful Storybook stories for UI components.
Table of Contents¶
Story Structure¶
Every Storybook story file should follow this consistent structure:
import React from 'react';
import type { Meta, StoryObj } from '@storybook/nextjs';
// Import required icons from lucide-react
// Import component from relative path
import { YourComponent } from './YourComponent';
const meta: Meta<typeof YourComponent> = {
title: 'Components/YourComponent', // No category subfolder in title
component: YourComponent,
parameters: {
layout: 'padded', // or 'centered', 'fullscreen'
docs: {
description: {
component: `Brief description of the component.
## Features
- **Feature 1**: Description of the feature
- **Feature 2**: Description of the feature
- **Feature 3**: Description of the feature
// ... 8-12 features total
## Usage
\`\`\`tsx
import { YourComponent } from '@/components/ui/YourComponent';
// Basic usage example
<YourComponent
prop1="value"
prop2={true}
/>
// Advanced usage example
<YourComponent
prop1="value"
prop2={true}
onAction={(data) => console.log(data)}
>
{children}
</YourComponent>
\`\`\``,
},
},
},
tags: ['autodocs'],
argTypes: {
// Define controls for interactive props
prop1: {
control: 'text',
description: 'Description of prop1',
table: {
type: { summary: 'string' },
defaultValue: { summary: 'default' },
},
},
// Hide non-essential props from controls
internalProp: { table: { disable: true } },
},
};
export default meta;
type Story = StoryObj<typeof meta>;
// Define your stories
export const Default: Story = {
args: {
// Default props
},
};
Documentation Pattern¶
Component Description¶
The component description should include:
- Brief Overview (1-2 sentences)
- What the component does
-
When to use it
-
Features Section
- 8-12 bullet points
- Each feature should be bold with a colon
-
Cover:
- Core functionality
- Visual variants
- Interaction patterns
- Accessibility features
- Integration capabilities
- Customization options
-
Usage Section
- Import statement
- Basic usage example
- Common variations
- Advanced usage (if applicable)
- Integration examples (for complex components)
Example Documentation¶
description: {
component: `A flexible button component that supports multiple variants, sizes, and states. Use it for triggering actions and navigation throughout your application.
## Features
- **Multiple Variants**: Default, destructive, outline, secondary, ghost, and link styles
- **Flexible Sizing**: Small, default, and large sizes for different contexts
- **Loading State**: Built-in loading spinner with disabled interaction
- **Icon Support**: Leading and trailing icons with automatic spacing
- **Full Accessibility**: ARIA attributes, keyboard navigation, and focus management
- **Asynchronous Actions**: Handles async onClick handlers with loading state
- **Link Support**: Can render as anchor tag with href prop
- **Custom Styling**: Accepts className for additional customization
- **Disabled State**: Visual and interaction feedback for disabled buttons
- **Keyboard Shortcuts**: Support for keyboard shortcuts with tooltips
- **Animation Effects**: Smooth transitions and hover effects
- **Theme Aware**: Automatically adapts to light/dark themes
## Usage
\`\`\`tsx
import { Button } from '@/components/ui/Button';
import { SendIcon } from 'lucide-react';
// Basic button
<Button onClick={() => console.log('clicked')}>
Click me
</Button>
// Button with icon
<Button>
<SendIcon className="mr-2 h-4 w-4" />
Send Message
</Button>
// Loading state
<Button loading>
Processing...
</Button>
// As a link
<Button asChild>
<a href="/dashboard">Go to Dashboard</a>
</Button>
\`\`\``,
}
Best Practices¶
1. Story Naming¶
- Use descriptive names that indicate the story's purpose
- Common story names:
Default- Basic component usageWithIcons- Component with icon examplesAllVariants- Shows all visual variantsInteractive- Demonstrates interactionsControlled- Controlled component exampleWithValidation- Form components with validationLoading- Loading statesError- Error statesDisabled- Disabled states
2. ArgTypes Configuration¶
argTypes: {
// Text controls
label: {
control: 'text',
description: 'Button label text',
},
// Select controls
variant: {
control: 'select',
options: ['default', 'destructive', 'outline'],
description: 'Visual style variant',
},
// Boolean controls
disabled: {
control: 'boolean',
description: 'Disables the button',
},
// Action logging
onClick: {
action: 'clicked',
description: 'Called when button is clicked',
},
// Hide internal props
internalState: {
table: { disable: true },
},
}
3. Parameters¶
parameters: {
// Layout options
layout: 'centered', // 'padded' | 'fullscreen'
// Viewport configuration
viewport: {
defaultViewport: 'mobile1',
},
// Backgrounds
backgrounds: {
default: 'light',
},
// Story-specific docs
docs: {
description: {
story: 'This story demonstrates...',
},
},
}
4. Decorators¶
Use decorators for:
- Providing context/providers
- Adding layout wrappers
- Setting up mock data
decorators: [
(Story) => (
<div className="min-h-[400px] flex items-center justify-center">
<Story />
</div>
),
]
Code Examples¶
Simple Component Story¶
// Badge.stories.tsx
const meta: Meta<typeof Badge> = {
title: 'Components/Badge',
component: Badge,
parameters: {
layout: 'centered',
docs: {
description: {
component: `Badges are used to highlight important information. They provide visual indicators for status, counts, or categories.
## Features
- **Multiple Variants**: Default, secondary, destructive, and outline styles
- **Flexible Content**: Can contain text, numbers, or icons
- **Accessible**: Proper ARIA attributes for screen readers
- **Theme Integration**: Adapts to light/dark themes automatically
## Usage
\`\`\`tsx
import { Badge } from '@/components/ui/Badge';
// Basic usage
<Badge>New</Badge>
// With variants
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Error</Badge>
<Badge variant="outline">Outline</Badge>
\`\`\``,
},
},
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'secondary', 'destructive', 'outline'],
},
children: {
control: 'text',
},
},
};
export const Default: Story = {
args: {
children: 'Badge',
},
};
export const AllVariants: Story = {
render: () => (
<div className="flex gap-2">
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="outline">Outline</Badge>
</div>
),
};
Complex Component Story¶
// DataTable.stories.tsx
const meta: Meta<typeof DataTable<User>> = {
title: 'Components/DataTable',
component: DataTable,
parameters: {
layout: 'padded',
docs: {
description: {
component: `Comprehensive data table with sorting, filtering...`,
},
},
},
tags: ['autodocs'],
argTypes: {
// Complex type documentation
columns: {
description: 'Column definitions',
table: {
type: {
summary: 'ColumnDef<TData>[]',
detail: `{
id?: string,
header?: string,
accessorKey?: keyof TData,
// ... full type definition
}`,
},
},
},
},
};
// Interactive story with state
export const Interactive: Story = {
render: function Render(args) {
const [data, setData] = useState(initialData);
return (
<DataTable
{...args}
data={data}
onUpdate={(newData) => setData(newData)}
/>
);
},
};
Common Patterns¶
1. Render Functions for State¶
Use render functions when stories need internal state:
export const Controlled: Story = {
render: function Render() {
const [value, setValue] = useState('');
return (
<Input
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
},
};
2. Multiple Examples in One Story¶
export const Sizes: Story = {
render: () => (
<div className="space-y-4">
<Button size="sm">Small</Button>
<Button>Default</Button>
<Button size="lg">Large</Button>
</div>
),
parameters: {
docs: {
description: {
story: 'Available button sizes for different UI contexts.',
},
},
},
};
3. With Mock Data¶
const mockUsers = [
{ id: 1, name: 'John Doe', email: 'john@example.com' },
{ id: 2, name: 'Jane Smith', email: 'jane@example.com' },
];
export const WithData: Story = {
args: {
data: mockUsers,
},
};
4. Async Actions¶
export const AsyncAction: Story = {
args: {
onClick: async () => {
await sleep(2000);
console.log('Action completed');
},
},
};
Current Project Conventions¶
Based on the existing stories in this project:
Import Pattern¶
import React from 'react'; // Always import React
import type { Meta, StoryObj } from '@storybook/nextjs';
import { IconName } from 'lucide-react'; // Icons from lucide-react
import { Component } from './Component'; // Relative imports
Title Convention¶
- Use flat hierarchy:
'Components/ComponentName' - Don't use nested categories in the title
Layout Options¶
'centered'- For small, focused components (buttons, badges, inputs)'padded'- For larger components that need space (cards, tables, alerts)'fullscreen'- For full-page layouts
Documentation Style¶
Each component description should follow this exact format:
- Opening sentence describing what the component does
- Optional second sentence about when to use it
- Features section with 4-12 bullet points
- Usage section with practical code examples
- Optional Accessibility section for complex components
Story Naming Patterns¶
Default- Basic component with minimal propsSecondary,Destructive,Outline- Variant examplesSmall,Large- Size variationsDisabled- Disabled stateLoading- Loading stateAllVariants- Shows all variants in one storyAllSizes- Shows all sizes in one storyWithIcon- Component with icon examplesInteractive- Demonstrates user interactions
Farm Cove Specific¶
Some stories include a FarmCoveThemeShowcase story that demonstrates:
- Brand colors (Primary Teal, Success, Warning, etc.)
- Farm Cove specific UI patterns
- Film production context examples
- WCAG compliance notes
Summary¶
Good Storybook stories should:
- Be Comprehensive: Cover all major use cases and variants
- Be Documented: Include features list and usage examples
- Be Interactive: Use controls for props that users might want to adjust
- Be Realistic: Use realistic mock data and scenarios
- Be Organized: Follow consistent naming and structure
- Be Helpful: Include code examples that developers can copy
- Be Accessible: Demonstrate accessibility features
- Be Visual: Show all visual states and variants
Remember: Storybook stories are both documentation and development tools. They should help developers understand how to use components and serve as a visual regression testing tool.