Skip to main content

Component Design Checklist

When to use: Building new UI components. Reviewing component architecture.

The test: Can this component be used in isolation? Can it be understood in under 30 seconds?


Component Creation Checklist

Run this for every new component:

  • Named component - No anonymous exports
  • TypeScript interface - Props defined with types
  • Semantic HTML - article, section, button - not div soup
  • Design tokens - No arbitrary values (use theme)
  • Destructured props - With default values
  • Single responsibility - Does one thing well
  • Independently testable - Works in isolation

Component Types

TypePurposeData SourceLocation
PresentationalDisplay UIProps onlyReusable library
StructuralCompose layoutProps, maps dataPages/views
StatefulManage stateAPI, contextApp-specific

Rule of Thumb

  • Bottom of tree → Presentational (most reusable)
  • Middle of tree → Structural (compose others)
  • Top of tree → Stateful (app-specific)

Props Design

Checklist

  • Props destructured at function signature
  • Defaults assigned during destructuring
  • No more than 5-7 props (split if more)
  • No boolean props for complex states
  • Children over render props where possible

Good Example

interface CardProps {
title: string;
description: string;
variant?: 'default' | 'highlighted';
onAction?: () => void;
}

function Card({
title,
description,
variant = 'default',
onAction
}: CardProps) {
// ...
}

Bad Component Signals

SignalProblemFix
Too many propsToo many responsibilitiesSplit into smaller components
Breaks when movedToo coupledAccept data via props
Hard to testHidden dependenciesInject dependencies
Render props hellOver-abstractionUse children or composition
Prop drillingWrong tree structureUse context or restructure

File Organization

src/components/
├── design-system/ # Presentational (most reusable)
│ ├── Button.tsx
│ ├── Typography.tsx
│ └── Card.tsx
├── features/ # Structural (feature-specific)
│ ├── auth/
│ └── dashboard/
└── pages/ # Stateful (app-specific)
└── HomePage.tsx

Conditional Rendering

Checklist

  • No nested ternaries
  • Early returns for error/loading states
  • Logical && only for simple cases
  • Named variables for complex conditions

Good Example

function UserProfile({ user, isLoading, error }) {
if (isLoading) return <Skeleton />;
if (error) return <ErrorState error={error} />;
if (!user) return null;

return <Profile user={user} />;
}

Avoid These Anti-Patterns

  • No nested render functions - Extract to components
  • No inline object props - Creates new reference each render
  • No index as key - Use stable IDs
  • No side effects in render - Use useEffect
  • No direct DOM manipulation - Use refs

Testing Checklist

  • Component renders without crashing
  • Props produce expected output
  • Events trigger correct callbacks
  • Accessibility attributes present
  • Works in Storybook isolation

References