Skip to content

Component Standards & Best Practices โ€‹

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 TypeUse ForExample
textStrings, contentchildren, label, placeholder
booleanTrue/falsedisabled, loading, isOpen
numberNumberswidth, height, delay
rangeNumbers with slidersize: { type: 'range', min: 12, max: 64 }
colorColorsbackgroundColor, borderColor
selectDropdown (few options)variant, size, position
radioRadio buttonssize: ['sm', 'md', 'lg']
dateDatesstartDate, endDate
objectComplex objectsconfig, options
arrayArraysitems, 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, labels
  • Appearance - Visual styling, variants, colors
  • State - disabled, loading, error states
  • Events - onClick, onChange, etc.
  • Accessibility - ARIA attributes
  • Testing - backgroundColor, style overrides
  • Advanced - 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
  • [ ] backgroundColor control 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 โ€‹

Built with VitePress