storybook-story-writing
$
npx mdskill add TheBushidoCollective/han/storybook-story-writingGenerate valid CSF3 Storybook stories with proper component variations.
- Creates maintainable story files showcasing component states and props.
- Reads component definitions and applies CSF3 object syntax formatting.
- Executes Bash and Glob tools to locate and modify story files.
- Outputs corrected story code ready for Storybook build verification.
SKILL.md
.github/skills/storybook-story-writingView on GitHub ↗
---
name: storybook-story-writing
user-invocable: false
description: Use when creating or modifying Storybook stories for components. Ensures stories follow CSF3 format, properly showcase component variations, and build successfully.
allowed-tools:
- Read
- Write
- Edit
- Bash
- Grep
- Glob
---
# Storybook - Story Writing
Write well-structured, maintainable Storybook stories using Component Story Format 3 (CSF3) that showcase component variations and ensure consistent rendering.
## Key Concepts
### Component Story Format 3 (CSF3)
CSF3 is the modern Storybook format that uses object syntax for stories:
```typescript
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
backgroundColor: { control: 'color' },
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
},
};
export const Secondary: Story = {
args: {
label: 'Button',
},
};
```
### Story Organization
- One story file per component: `Component.stories.tsx`
- Use descriptive story names: `Primary`, `Secondary`, `Large`, `Disabled`
- Group related stories under a title hierarchy: `Components/Forms/Input`
### Default Export (Meta)
The default export defines metadata for all stories:
```typescript
const meta = {
title: 'Components/Button', // Navigation path
component: Button, // Component reference
parameters: {}, // Story-level config
tags: ['autodocs'], // Enable auto-documentation
argTypes: {}, // Control types
decorators: [], // Wrappers for stories
} satisfies Meta<typeof Button>;
```
## Best Practices
### 1. Use TypeScript for Type Safety
```typescript
import type { Meta, StoryObj } from '@storybook/react';
const meta = {
component: Button,
} satisfies Meta<typeof Button>;
type Story = StoryObj<typeof meta>;
```
### 2. Show All Component States
Create stories for each meaningful state:
```typescript
export const Default: Story = {
args: {
label: 'Click me',
},
};
export const Loading: Story = {
args: {
label: 'Loading...',
loading: true,
},
};
export const Disabled: Story = {
args: {
label: 'Disabled',
disabled: true,
},
};
export const WithIcon: Story = {
args: {
label: 'Download',
icon: 'download',
},
};
```
### 3. Use Sensible Defaults
```typescript
export const Primary: Story = {
args: {
primary: true,
label: 'Button',
size: 'medium',
},
};
// Extend existing stories
export const PrimaryLarge: Story = {
...Primary,
args: {
...Primary.args,
size: 'large',
},
};
```
### 4. Add Descriptive Parameters
```typescript
export const WithTooltip: Story = {
args: {
label: 'Hover me',
tooltip: 'Click to submit',
},
parameters: {
docs: {
description: {
story: 'Shows a tooltip on hover to provide additional context.',
},
},
},
};
```
### 5. Use Decorators for Context
```typescript
import { RouterDecorator } from '../decorators';
const meta = {
component: Navigation,
decorators: [
(Story) => (
<div style={{ padding: '3rem' }}>
<Story />
</div>
),
RouterDecorator,
],
} satisfies Meta<typeof Navigation>;
```
## Common Patterns
### Form Components
```typescript
export const EmptyForm: Story = {
args: {
onSubmit: (data) => console.log(data),
},
};
export const PrefilledForm: Story = {
args: {
defaultValues: {
email: 'user@example.com',
name: 'John Doe',
},
},
};
export const WithValidationErrors: Story = {
args: {
errors: {
email: 'Invalid email format',
name: 'Name is required',
},
},
};
```
### Layout Components
```typescript
export const WithSidebar: Story = {
args: {
sidebar: <Sidebar items={sidebarItems} />,
children: <Content />,
},
parameters: {
layout: 'fullscreen',
},
};
```
### Data-Driven Components
```typescript
const mockData = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
export const WithData: Story = {
args: {
items: mockData,
},
};
export const Empty: Story = {
args: {
items: [],
emptyMessage: 'No items found',
},
};
```
### Responsive Components
```typescript
export const Mobile: Story = {
args: {
variant: 'mobile',
},
parameters: {
viewport: {
defaultViewport: 'mobile1',
},
},
};
export const Desktop: Story = {
args: {
variant: 'desktop',
},
parameters: {
viewport: {
defaultViewport: 'desktop',
},
},
};
```
## Anti-Patterns
### ❌ Don't Use Template Binding (CSF2)
```typescript
// Bad - Old CSF2 format
const Template = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = { label: 'Button' };
```
```typescript
// Good - CSF3 format
export const Primary: Story = {
args: { label: 'Button' },
};
```
### ❌ Don't Mix Logic in Stories
```typescript
// Bad
export const Complex: Story = {
render: (args) => {
const [state, setState] = useState(false);
useEffect(() => {
// Complex side effects
}, []);
return <Component {...args} />;
},
};
```
```typescript
// Good - Move logic to component or use play functions
export const Complex: Story = {
args: { initialState: false },
};
```
### ❌ Don't Hardcode Repetitive Props
```typescript
// Bad
export const Story1: Story = {
args: { label: 'Button', size: 'medium', theme: 'light' },
};
export const Story2: Story = {
args: { label: 'Submit', size: 'medium', theme: 'light' },
};
```
```typescript
// Good - Use meta-level defaults
const meta = {
component: Button,
args: {
size: 'medium',
theme: 'light',
},
} satisfies Meta<typeof Button>;
export const Story1: Story = {
args: { label: 'Button' },
};
export const Story2: Story = {
args: { label: 'Submit' },
};
```
### ❌ Don't Skip Story Types
```typescript
// Bad - Missing type annotation
export const Primary = {
args: { label: 'Button' },
};
```
```typescript
// Good - With type
export const Primary: Story = {
args: { label: 'Button' },
};
```
## Related Skills
- **storybook-args-controls**: Advanced arg configuration and interactive controls
- **storybook-play-functions**: Automated interaction testing within stories
- **storybook-component-documentation**: Auto-generating component documentation
More from TheBushidoCollective/han
- absinthe-resolversUse when implementing GraphQL resolvers with Absinthe. Covers resolver patterns, dataloader integration, batching, and error handling.
- absinthe-schemaUse when designing GraphQL schemas with Absinthe. Covers type definitions, interfaces, unions, enums, and schema organization patterns.
- absinthe-subscriptionsUse when implementing real-time GraphQL subscriptions with Absinthe. Covers Phoenix channels, PubSub, and subscription patterns.
- act-docker-setupUse when configuring Docker environments for act, selecting runner images, managing container resources, or troubleshooting Docker-related issues with local GitHub Actions testing.
- act-local-testingUse when testing GitHub Actions workflows locally with act. Covers act CLI usage, Docker configuration, debugging workflows, and troubleshooting common issues when running workflows on your local machine.
- act-workflow-syntaxUse when creating or modifying GitHub Actions workflow files. Provides guidance on workflow syntax, triggers, jobs, steps, and expressions for creating valid GitHub Actions workflows that can be tested locally with act.
- ameba-configurationUse when configuring Ameba rules and settings for Crystal projects including .ameba.yml setup, rule management, severity levels, and code quality enforcement.
- ameba-custom-rulesUse when creating custom Ameba rules for Crystal code analysis including rule development, AST traversal, issue reporting, and rule testing.
- ameba-integrationUse when integrating Ameba into development workflows including CI/CD pipelines, pre-commit hooks, GitHub Actions, and automated code review processes.
- analyze-performanceAnalyze performance metrics and identify slow transactions in Sentry