Component Standards & Best Practices โ
Recommended Props for Every Component โ
Essential Props (Include in Most Components) โ
jsx
{
children, // Content/nested elements
className, // Custom styling
variant, // Visual variants (primary, secondary, etc.)
disabled, // Disabled state (for interactive components)
onClick, // Click handler (for interactive components)
'aria-label', // Accessibility label
}Testing/Override Props โ
jsx
{
backgroundColor, // Color picker for testing
style, // Inline style override
size, // Size variants (small, medium, large)
}Standard Storybook Controls โ
1. Content Controls โ
jsx
children: {
control: 'text',
description: 'Content inside the component',
table: { category: 'Content' }
}2. Appearance Controls โ
jsx
variant: {
control: 'select',
options: ['default', 'primary', 'secondary', 'ghost'],
description: 'Visual style variant',
table: { category: 'Appearance' }
},
size: {
control: 'radio', // or 'select' for many options
options: ['small', 'medium', 'large'],
description: 'Component size',
table: { category: 'Appearance' }
},
backgroundColor: {
control: 'color',
description: 'Override background color (for testing)',
table: { category: 'Testing' }
}3. State Controls โ
jsx
disabled: {
control: 'boolean',
description: 'Disabled state',
table: { category: 'State' }
},
loading: {
control: 'boolean',
description: 'Loading state',
table: { category: 'State' }
},
error: {
control: 'boolean',
description: 'Error state',
table: { category: 'State' }
}4. Event Controls โ
jsx
onClick: {
action: 'clicked',
description: 'Click handler',
table: { category: 'Events' }
},
onChange: {
action: 'changed',
description: 'Change handler',
table: { category: 'Events' }
},
onSubmit: {
action: 'submitted',
description: 'Submit handler',
table: { category: 'Events' }
}5. Accessibility Controls โ
jsx
'aria-label': {
control: 'text',
description: 'Accessibility label for screen readers',
table: { category: 'Accessibility' }
},
'aria-disabled': {
control: 'boolean',
description: 'ARIA disabled state',
table: { category: 'Accessibility' }
}Control Types Reference โ
| Control Type | Use For | Example |
|---|---|---|
text | Strings, content | children, label, placeholder |
boolean | True/false | disabled, loading, isOpen |
number | Numbers | width, height, delay |
range | Numbers with slider | size: { type: 'range', min: 12, max: 64 } |
color | Colors | backgroundColor, borderColor |
select | Dropdown (few options) | variant, size, position |
radio | Radio buttons | size: ['sm', 'md', 'lg'] |
date | Dates | startDate, endDate |
object | Complex objects | config, options |
array | Arrays | items, options |
Organizing Controls with Categories โ
Group controls for better UX:
jsx
argTypes: {
children: {
control: 'text',
table: { category: 'Content' } // โ Groups in tabs
},
variant: {
control: 'select',
table: { category: 'Appearance' }
},
onClick: {
action: 'clicked',
table: { category: 'Events' }
}
}Categories:
Content- Text, children, labelsAppearance- Visual styling, variants, colorsState- disabled, loading, error statesEvents- onClick, onChange, etc.Accessibility- ARIA attributesTesting- backgroundColor, style overridesAdvanced- className, custom props
Standard Story Set โ
Include these stories for every component:
jsx
// 1. Default/Base state
export const Default = {
args: { children: 'Default' }
}
// 2. Each variant
export const Primary = {
args: { variant: 'primary', children: 'Primary' }
}
export const Secondary = {
args: { variant: 'secondary', children: 'Secondary' }
}
// 3. Interactive states
export const Disabled = {
args: { disabled: true, children: 'Disabled' }
}
export const Loading = {
args: { loading: true, children: 'Loading' }
}
// 4. Size variants
export const Small = {
args: { size: 'small', children: 'Small' }
}
export const Large = {
args: { size: 'large', children: 'Large' }
}
// 5. Edge cases
export const LongText = {
args: {
children: 'This is a very long text that tests wrapping and overflow behavior'
}
}
export const Empty = {
args: { children: '' }
}Component Implementation Pattern โ
jsx
export default function Component({
// Group props logically
children,
className = '',
// Variants
variant = 'default',
size = 'medium',
// States
disabled = false,
loading = false,
// Testing overrides
backgroundColor,
style,
// Events
onClick,
// Accessibility
'aria-label': ariaLabel,
...props
}) {
// Combine styles
const combinedStyle = {
...(backgroundColor && { backgroundColor }),
...style
}
return (
<element
className={`base ${variant} ${size} ${className}`}
disabled={disabled}
onClick={!disabled ? onClick : undefined}
aria-label={ariaLabel}
style={combinedStyle}
{...props}
>
{loading ? <Spinner /> : children}
</element>
)
}Quick Checklist โ
When creating a new component:
- [ ] Component accepts standard props (children, className, variant)
- [ ] Story file imports the component
- [ ]
tags: ['autodocs']enabled - [ ] Controls grouped into categories
- [ ]
backgroundColorcontrol for testing - [ ] Event handlers use
action: 'eventName' - [ ] Accessibility props included
- [ ] Stories for: Default, Variants, States, Sizes
- [ ] Edge cases tested (long text, empty, disabled)
See Also โ
- .storybook-template.jsx - Copy this for new components
- Button.jsx - Example implementation
- Button.stories.jsx - Example story