Storybook Generator
Storybook Generator Skill
This skill generates comprehensive, consistent Storybook documentation for components following established patterns in the myOperator UI library.
When to Activate
Activate this skill when:
- Creating a new component
- Updating component documentation
- Adding usage examples
- Documenting design tokens
- Creating interactive stories
Documentation Pattern
Follow the Button and AlertConfiguration component documentation structure:
Required Sections
- Installation - CLI command for users
- Import - How to import the component
- Design Tokens - Table of CSS variables used
- Typography (if applicable) - Font specifications
- Usage Examples - Code snippets
- Interactive Stories - Playground for each variant
Story File Structure
import type { Meta, StoryObj } from '@storybook/react'
import { Component } from './component'
/**
* Component description with comprehensive documentation.
*
* ## Installation
*
* Install via the myOperator UI CLI:
* ```bash
* npx myoperator-ui add component-name
* ```
*
* ## Import
*
* ```tsx
* import { Component } from "@myoperator/ui"
* ```
*
* ## Design Tokens
*
* [Design tokens table - see examples below]
*
* ## Typography (if applicable)
*
* [Typography table - see examples below]
*
* ## Usage
*
* ```tsx
* <Component variant="primary" size="lg">
* Content
* </Component>
* ```
*/
const meta: Meta<typeof Component> = {
// Title depends on component type and sub-group:
// UI component: 'Components/ComponentName'
// Custom (no sub-group): 'Custom/ComponentName'
// Custom (with sub-group): 'Custom/SubGroup/ComponentName'
title: 'Components/ComponentName',
component: Component,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'primary', 'secondary'],
description: 'Visual style variant',
table: {
defaultValue: { summary: 'default' },
},
},
size: {
control: 'select',
options: ['sm', 'default', 'lg'],
description: 'Size of the component',
table: {
defaultValue: { summary: 'default' },
},
},
},
}
export default meta
type Story = StoryObj<typeof meta>
// Stories...
Design Tokens Table
Format
The design tokens table must document all CSS variables used in the component:
## Design Tokens
| Token | CSS Variable | Usage | Preview |
|-------|--------------|-------|---------|
| Background Primary | \`--semantic-bg-primary\` | Component background | <div style="width: 20px; height: 20px; background: var(--semantic-bg-primary); border: 1px solid #ccc;"></div> |
| Text Primary | \`--semantic-text-primary\` | Primary text color | <span style="color: var(--semantic-text-primary);">Aa</span> |
| Border Layout | \`--semantic-border-layout\` | Container borders | <div style="width: 40px; height: 2px; background: var(--semantic-border-layout);"></div> |
How to Generate
-
Extract CSS variables from component code:
// From this code: className="bg-primary text-primary-foreground border-input" // Extract these variables: - --primary (bg-primary) - --primary-foreground (text-primary-foreground) - --input (border-input) -
Categorize by usage:
- Backgrounds:
bg-*classes - Text colors:
text-*classes - Borders:
border-*classes - Other: Shadows, rings, etc.
- Backgrounds:
-
Add appropriate preview:
- Backgrounds: Color swatch (20x20px div)
- Text: "Aa" sample with color
- Borders: Line sample (40x2px div)
Examples
Example 1: Button Component
## Design Tokens
| Token | CSS Variable | Usage | Preview |
|-------|--------------|-------|---------|
| Primary | \`--primary\` | Primary button background | <div style="width: 20px; height: 20px; background: var(--primary); border-radius: 4px;"></div> |
| Primary Foreground | \`--primary-foreground\` | Text on primary button | <span style="color: var(--primary-foreground);">Aa</span> |
| Secondary | \`--secondary\` | Secondary button background | <div style="width: 20px; height: 20px; background: var(--secondary); border-radius: 4px;"></div> |
| Destructive | \`--destructive\` | Destructive button background | <div style="width: 20px; height: 20px; background: var(--destructive); border-radius: 4px;"></div> |
| Border | \`--border\` | Outline variant border | <div style="width: 40px; height: 2px; background: var(--border);"></div> |
Example 2: AlertConfiguration Component
## Design Tokens
| Token | CSS Variable | Usage | Preview |
|-------|--------------|-------|---------|
| Border Layout | \`--semantic-border-layout\` | Container border, dividers | <div style="width: 40px; height: 2px; background: var(--semantic-border-layout);"></div> |
| Background Primary | \`--semantic-bg-primary\` | Component background | <div style="width: 20px; height: 20px; background: var(--semantic-bg-primary); border: 1px solid #ccc;"></div> |
| Text Primary | \`--semantic-text-primary\` | Labels and values | <span style="color: var(--semantic-text-primary);">Aa</span> |
| Text Muted | \`--semantic-text-muted\` | Descriptions | <span style="color: var(--semantic-text-muted);">Aa</span> |
| Text Link | \`--semantic-text-link\` | Top-up amount (blue) | <span style="color: var(--semantic-text-link);">Aa</span> |
| Error Primary | \`--semantic-error-primary\` | Negative balance (red) | <span style="color: var(--semantic-error-primary);">Aa</span> |
Typography Table
Format
Document font specifications for text elements in the component:
## Typography
| Element | Font Size | Line Height | Weight | Letter Spacing |
|---------|-----------|-------------|--------|----------------|
| Title | 16px (\`text-base\`) | 24px (\`leading-6\`) | 600 (\`font-semibold\`) | 0px (\`tracking-[0px]\`) |
| Subtitle | 14px (\`text-sm\`) | 20px (\`leading-5\`) | 400 (\`font-normal\`) | 0.035px (\`tracking-[0.035px]\`) |
How to Generate
-
Identify text elements:
- Titles/headers
- Body text
- Labels
- Descriptions
- Captions
-
Extract Tailwind classes:
// From this code: <h3 className="text-base font-semibold tracking-[0px]"> // Extract: - Font Size: 16px (text-base) - Weight: 600 (font-semibold) - Letter Spacing: 0px (tracking-[0px]) -
Map to actual values:
text-sm = 14px text-base = 16px text-lg = 18px font-normal = 400 font-medium = 500 font-semibold = 600 font-bold = 700 leading-tight = 1.25 leading-normal = 1.5 leading-relaxed = 1.625
Example
AlertConfiguration Typography:
## Typography
| Element | Font Size | Line Height | Weight | Letter Spacing |
|---------|-----------|-------------|--------|----------------|
| Title | 16px (\`text-base\`) | 24px (\`leading-6\`) | 600 (\`font-semibold\`) | 0px (\`tracking-[0px]\`) |
| Description | 14px (\`text-sm\`) | 20px (\`leading-relaxed\`) | 400 (\`font-normal\`) | 0.035px (\`tracking-[0.035px]\`) |
| Label | 14px (\`text-sm\`) | 20px | 600 (\`font-semibold\`) | 0.014px (\`tracking-[0.014px]\`) |
| Value | 14px (\`text-sm\`) | 20px | 400 (\`font-normal\`) | 0.035px (\`tracking-[0.035px]\`) |
Usage Examples
Basic Usage
<Component variant="primary" size="lg">
Content
</Component>
Advanced Usage
Show composition patterns, controlled state, callbacks:
const [open, setOpen] = useState(false)
<Component
open={open}
onOpenChange={setOpen}
variant="primary"
onAction={handleAction}
>
<ComponentContent />
</Component>
With Form Integration
const [value, setValue] = useState('')
<FormModal
open={isOpen}
onOpenChange={setIsOpen}
title="Edit Values"
onSave={handleSave}
>
<TextField
label="Name"
value={value}
onChange={(e) => setValue(e.target.value)}
/>
</FormModal>
Interactive Stories
Create stories for each variant and use case:
1. Default Story
export const Default: Story = {
args: {
children: 'Component',
},
}
2. Variant Stories
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Primary Component',
},
}
export const Secondary: Story = {
args: {
variant: 'secondary',
children: 'Secondary Component',
},
}
export const Destructive: Story = {
args: {
variant: 'destructive',
children: 'Destructive Component',
},
}
3. Size Stories
export const Small: Story = {
args: {
size: 'sm',
children: 'Small Component',
},
}
export const Large: Story = {
args: {
size: 'lg',
children: 'Large Component',
},
}
4. Interactive Stories
export const WithState: Story = {
render: () => {
const [open, setOpen] = React.useState(false)
return (
<>
<Button onClick={() => setOpen(true)}>
Open Component
</Button>
<Component
open={open}
onOpenChange={setOpen}
/>
</>
)
},
}
5. Showcase Stories
export const AllVariants: Story = {
render: () => (
<div className="flex flex-col gap-4">
<div className="flex gap-2">
<Component variant="default">Default</Component>
<Component variant="primary">Primary</Component>
<Component variant="secondary">Secondary</Component>
</div>
<div className="flex gap-2">
<Component size="sm">Small</Component>
<Component size="default">Default</Component>
<Component size="lg">Large</Component>
</div>
</div>
),
}
6. State Stories
export const States: Story = {
render: () => (
<div className="flex flex-col gap-4">
<Component>Normal</Component>
<Component disabled>Disabled</Component>
<Component loading>Loading</Component>
</div>
),
}
7. Multi-State Stories (from State Inventory Table)
If the component has a State Inventory Table from Phase 2, create a story for each visual state:
// Example: WalletTopup has Default, No Preselection, Loading, and Disabled states
export const Default: Story = {
args: {
amounts: [100, 200, 500],
selectedAmount: 100,
},
}
export const NoPreselection: Story = {
args: {
amounts: [100, 200, 500],
// no selectedAmount — tests empty/initial state
},
}
export const Loading: Story = {
args: {
amounts: [100, 200, 500],
isLoading: true,
},
}
export const Disabled: Story = {
args: {
amounts: [100, 200, 500],
disabled: true,
},
}
Rules for multi-state stories:
- Every state in the State Inventory Table MUST have a corresponding story
- Name stories to match the state names (e.g.,
Success,Error,Empty) - Show the visual difference clearly — don't just toggle a boolean, set all props that reflect that state
- If a state involves user interaction (e.g., after typing), use
renderwith internal state
8. Domain-Specific Prop Stories
For components with domain-specific props (confirmed in Phase 5, Step 1e), create stories demonstrating key prop combinations:
// Example: WalletTopup has currency, voucherLink, amounts, headerIcon
export const DollarCurrency: Story = {
args: {
currency: '$',
amounts: [10, 25, 50, 100],
},
}
export const CustomVoucherIcon: Story = {
args: {
amounts: [100, 200, 500],
headerIcon: <Gift className="h-5 w-5" />,
},
}
export const NoVoucherLink: Story = {
args: {
amounts: [100, 200, 500],
showVoucherLink: false,
},
}
Rules for domain-specific prop stories:
- Cover each customization prop with at least one story
- Show non-obvious defaults (e.g., what happens when a prop is omitted)
- Use descriptive story names that explain the prop being demonstrated
ArgTypes Configuration
Document all props with descriptions and controls:
argTypes: {
variant: {
control: 'select',
options: ['default', 'primary', 'secondary', 'destructive'],
description: 'Visual style variant of the component',
table: {
defaultValue: { summary: 'default' },
type: { summary: 'string' },
},
},
size: {
control: 'select',
options: ['sm', 'default', 'lg', 'xl'],
description: 'Size of the component',
table: {
defaultValue: { summary: 'default' },
type: { summary: 'string' },
},
},
disabled: {
control: 'boolean',
description: 'Disables the component interaction',
table: {
defaultValue: { summary: false },
type: { summary: 'boolean' },
},
},
loading: {
control: 'boolean',
description: 'Shows loading state',
table: {
defaultValue: { summary: false },
type: { summary: 'boolean' },
},
},
onAction: {
action: 'clicked',
description: 'Callback when action is triggered',
table: {
type: { summary: '() => void' },
},
},
}
Domain-Specific ArgTypes
For components with domain-specific props, document all three categories:
argTypes: {
// Data props
amounts: {
control: 'object',
description: 'Array of preset amounts to display',
table: {
type: { summary: 'number[]' },
defaultValue: { summary: '[100, 200, 500, 1000]' },
},
},
currency: {
control: 'text',
description: 'Currency symbol to display',
table: {
type: { summary: 'string' },
defaultValue: { summary: '₹' },
},
},
// Callback props
onSubmit: {
action: 'submitted',
description: 'Called when user submits with the selected/entered amount',
table: {
type: { summary: '(amount: number) => void' },
},
},
// Customization props
headerIcon: {
control: false,
description: 'Custom icon for the header. Defaults to Wallet icon.',
table: {
type: { summary: 'React.ReactNode' },
},
},
}
Complete Example
Button Component Story:
import type { Meta, StoryObj } from '@storybook/react'
import { Button } from './button'
import { Loader2, Plus } from 'lucide-react'
/**
* A customizable button component with multiple variants, sizes, and icon support.
*
* ## Installation
*
* Install via the myOperator UI CLI:
* ```bash
* npx myoperator-ui add button
* ```
*
* ## Import
*
* ```tsx
* import { Button } from "@myoperator/ui"
* ```
*
* ## Design Tokens
*
* | Token | CSS Variable | Usage | Preview |
* |-------|--------------|-------|---------|
* | Primary | \`--primary\` | Primary button background | <div style="width: 20px; height: 20px; background: var(--primary); border-radius: 4px;"></div> |
* | Primary Foreground | \`--primary-foreground\` | Text on primary button | <span style="color: var(--primary-foreground);">Aa</span> |
* | Secondary | \`--secondary\` | Secondary button background | <div style="width: 20px; height: 20px; background: var(--secondary); border-radius: 4px;"></div> |
* | Destructive | \`--destructive\` | Destructive action background | <div style="width: 20px; height: 20px; background: var(--destructive); border-radius: 4px;"></div> |
* | Border | \`--border\` | Outline variant border | <div style="width: 40px; height: 2px; background: var(--border);"></div> |
*
* ## Usage
*
* ```tsx
* // Basic usage
* <Button variant="primary" size="lg">
* Click me
* </Button>
*
* // With icons
* <Button variant="default" leftIcon={<Plus />}>
* Add Item
* </Button>
*
* // Loading state
* <Button variant="primary" loading>
* Saving...
* </Button>
* ```
*/
const meta: Meta<typeof Button> = {
title: 'Components/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['default', 'primary', 'secondary', 'destructive', 'outline', 'ghost', 'link'],
description: 'Visual style variant',
table: {
defaultValue: { summary: 'default' },
},
},
size: {
control: 'select',
options: ['default', 'sm', 'lg', 'icon'],
description: 'Button size',
table: {
defaultValue: { summary: 'default' },
},
},
loading: {
control: 'boolean',
description: 'Shows loading spinner',
},
disabled: {
control: 'boolean',
description: 'Disables button interaction',
},
},
}
export default meta
type Story = StoryObj<typeof meta>
export const Default: Story = {
args: {
children: 'Button',
},
}
export const Primary: Story = {
args: {
variant: 'primary',
children: 'Primary Button',
},
}
export const AllVariants: Story = {
render: () => (
<div className="flex flex-wrap gap-4">
<Button variant="default">Default</Button>
<Button variant="primary">Primary</Button>
<Button variant="secondary">Secondary</Button>
<Button variant="destructive">Destructive</Button>
<Button variant="outline">Outline</Button>
<Button variant="ghost">Ghost</Button>
<Button variant="link">Link</Button>
</div>
),
}
export const WithIcons: Story = {
render: () => (
<div className="flex flex-wrap gap-4">
<Button leftIcon={<Plus className="h-4 w-4" />}>
Add Item
</Button>
<Button variant="primary" rightIcon={<Plus className="h-4 w-4" />}>
Add Item
</Button>
</div>
),
}
export const Loading: Story = {
render: () => (
<div className="flex flex-wrap gap-4">
<Button loading>Loading</Button>
<Button variant="primary" loading>
Saving...
</Button>
</div>
),
}
Best Practices
- Always include installation instructions - Help users get started
- Document all CSS variables used - Enable customization
- Show typography specifications - Ensure consistent implementation
- Provide usage examples - Demonstrate common patterns
- Create interactive stories - Let users explore variants
- Use meaningful story names - Make documentation discoverable
- Add descriptions to argTypes - Explain prop purposes
- Show composition patterns - Teach proper usage
- Include state examples - Cover disabled, loading, error states
- Follow established patterns - Maintain consistency across docs
Validation Checklist
Before finalizing documentation:
- Installation section included
- Import statement shown
- Design tokens table complete (all CSS variables from actual component code)
- Typography table included (if applicable)
- Usage examples provided
- Default story created
- Variant stories created
- Size stories created
- Interactive stories added
- Multi-state stories — one per state in the State Inventory Table
- Domain-specific prop stories — key customization props demonstrated
- ArgTypes configured (including domain-specific props with categories)
- All stories render correctly
- Documentation is clear and helpful
Post-Implementation Verification
After the component is fully implemented (Phase 5 complete), re-check:
- Design Tokens table reflects actual CSS variables in the final component code (not just the planned ones)
- Typography table matches actual font classes used
- Docs page description accurately reflects final props (props may have changed during implementation)
- Stories demonstrate the component's real behavior (not placeholder args)
- Sidebar grouping is correct (
Components/Namefor UI,Custom/NameorCustom/SubGroup/Namefor custom)
This skill ensures comprehensive, consistent documentation that helps users understand and use components effectively.