Component Architecture
Overview
Components are the building blocks of modern interfaces. A well-designed component system enables consistency, speeds up development, and makes maintenance easier. This skill teaches you to think about components systematically: designing for reusability, managing complexity, documenting thoroughly, and building a library that your team loves to use.
Core Methodology: Atomic Design
Atomic Design is a methodology for creating design systems by breaking down interfaces into fundamental building blocks.
The Five Levels
- Atoms The smallest, most basic components. They can't be broken down further without losing their meaning.
Examples: Button, Input, Label, Icon, Badge, Spinner
Characteristics:
-
Single responsibility
-
Highly reusable
-
No dependencies on other components (except styling)
-
Fully self-contained
Example Atom: Button
interface ButtonProps { variant?: 'primary' | 'secondary' | 'ghost'; size?: 'sm' | 'md' | 'lg'; disabled?: boolean; loading?: boolean; onClick?: () => void; children: React.ReactNode; }
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
disabled = false,
loading = false,
onClick,
children,
}) => {
return (
<button
className={button button--${variant} button--${size}}
disabled={disabled || loading}
onClick={onClick}
>
{loading && <Spinner size="sm" />}
{children}
</button>
);
};
- Molecules Groups of atoms bonded together to form relatively simple functional units.
Examples: Form Input (Label + Input + Error Message), Search Bar (Icon + Input + Button), Card Header (Avatar + Name + Date)
Characteristics:
-
Composed of atoms
-
Serve a specific purpose
-
Reusable across the product
-
Have a clear interface (props)
Example Molecule: Form Input
interface FormInputProps { label: string; placeholder?: string; error?: string; value: string; onChange: (value: string) => void; disabled?: boolean; }
export const FormInput: React.FC<FormInputProps> = ({ label, placeholder, error, value, onChange, disabled, }) => { return ( <div className="form-input"> <Label>{label}</Label> <Input placeholder={placeholder} value={value} onChange={(e) => onChange(e.target.value)} disabled={disabled} aria-invalid={!!error} /> {error && <ErrorMessage>{error}</ErrorMessage>} </div> ); };
- Organisms Relatively complex UI sections composed of groups of molecules and/or atoms and/or other organisms.
Examples: Navigation Bar, Form, Card, Modal, Sidebar
Characteristics:
-
Composed of molecules and atoms
-
Serve a specific business purpose
-
More complex interfaces
-
Often have state management
Example Organism: Card
interface CardProps { title: string; description?: string; image?: string; action?: { label: string; onClick: () => void; }; children?: React.ReactNode; }
export const Card: React.FC<CardProps> = ({ title, description, image, action, children, }) => { return ( <div className="card"> {image && <img src={image} alt={title} className="card-image" />} <div className="card-content"> <h3 className="card-title">{title}</h3> {description && <p className="card-description">{description}</p>} {children} {action && ( <Button onClick={action.onClick} variant="secondary"> {action.label} </Button> )} </div> </div> ); };
- Templates Page-level objects that place components into a layout and articulate the design's underlying content structure.
Examples: Blog Post Template, Product Page Template, Dashboard Template
Characteristics:
-
Composed of organisms, molecules, and atoms
-
Define page structure and layout
-
Show how components work together
-
Not typically reusable (specific to page type)
Example Template: Blog Post
export const BlogPostTemplate: React.FC<BlogPostTemplateProps> = ({ title, author, date, image, content, relatedPosts, }) => { return ( <div className="blog-post-template"> <Header /> <article className="blog-post"> <div className="blog-post-hero"> <img src={image} alt={title} /> </div> <div className="blog-post-content"> <h1>{title}</h1> <div className="blog-post-meta"> <Avatar src={author.avatar} alt={author.name} /> <span>{author.name}</span> <span>{formatDate(date)}</span> </div> <div className="blog-post-body">{content}</div> </div> </article> <section className="related-posts"> <h2>Related Posts</h2> <div className="related-posts-grid"> {relatedPosts.map((post) => ( <Card key={post.id} {...post} /> ))} </div> </section> <Footer /> </div> ); };
- Pages Specific instances of templates that show what the UI looks like with real data.
Examples: Homepage, Product Page, User Profile, Dashboard
Characteristics:
-
Instances of templates with real data
-
Used for testing and demonstration
-
Show how components behave with actual content
-
Help identify edge cases and issues
Component Design Principles
Principle 1: Single Responsibility
Each component should have one clear purpose. If a component does too much, break it down.
Bad:
// Does too much: rendering, data fetching, form handling, validation const UserProfile = () => { const [user, setUser] = useState(null); const [formData, setFormData] = useState({}); const [errors, setErrors] = useState({});
useEffect(() => { fetchUser().then(setUser); }, []);
const handleSubmit = () => { // validation logic // submission logic };
return ( // complex JSX ); };
Good:
// UserProfile: Orchestrates the page const UserProfile = () => { const { user } = useUser(); return ( <> <UserHeader user={user} /> <UserEditForm user={user} /> <UserActivity user={user} /> </> ); };
// UserHeader: Displays user info const UserHeader = ({ user }) => ( <div className="user-header"> <Avatar src={user.avatar} /> <h1>{user.name}</h1> </div> );
// UserEditForm: Handles form state and submission const UserEditForm = ({ user }) => { // form logic };
// UserActivity: Displays user activity const UserActivity = ({ user }) => { // activity logic };
Principle 2: Composition Over Inheritance
Build complex components by composing simpler ones, not by inheritance.
Bad:
// Inheritance approach (avoid) class Button extends React.Component {} class PrimaryButton extends Button {} class LargeButton extends Button {} class LargePrimaryButton extends Button {}
Good:
// Composition approach (prefer)
const Button = ({ variant = 'primary', size = 'md', ...props }) => (
<button className={button button--${variant} button--${size}} {...props} />
);
// Use composition to create variants const PrimaryButton = (props) => <Button variant="primary" {...props} />; const LargeButton = (props) => <Button size="lg" {...props} />; const LargePrimaryButton = (props) => <Button variant="primary" size="lg" {...props} />;
Principle 3: Props Interface Design
Design component props carefully. Props should be:
-
Intuitive — Props should be self-explanatory
-
Flexible — Props should support common use cases
-
Constrained — Props should prevent invalid states
-
Documented — Props should be clearly documented
Example: Well-Designed Props
interface ButtonProps { // Variant and size are constrained to valid options variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; size?: 'sm' | 'md' | 'lg';
// Boolean props are explicit disabled?: boolean; loading?: boolean; fullWidth?: boolean;
// Callbacks are clearly named onClick?: () => void; onHover?: () => void;
// Content is flexible children: React.ReactNode; icon?: React.ReactNode;
// HTML attributes can be passed through className?: string; 'aria-label'?: string; }
Principle 4: Controlled vs. Uncontrolled
Be explicit about whether a component is controlled (parent manages state) or uncontrolled (component manages state).
Controlled Component:
const ControlledInput = ({ value, onChange }) => ( <input value={value} onChange={(e) => onChange(e.target.value)} /> );
// Parent manages state const Parent = () => { const [value, setValue] = useState(''); return <ControlledInput value={value} onChange={setValue} />; };
Uncontrolled Component:
const UncontrolledInput = ({ defaultValue, onSubmit }) => { const inputRef = useRef(null);
return ( <> <input ref={inputRef} defaultValue={defaultValue} /> <button onClick={() => onSubmit(inputRef.current.value)}>Submit</button> </> ); };
// Parent doesn't manage state const Parent = () => { return <UncontrolledInput onSubmit={(value) => console.log(value)} />; };
Component Variants
Defining Variants
Variants are different versions of a component for different contexts. Define them clearly:
interface ButtonProps { variant?: 'primary' | 'secondary' | 'ghost' | 'danger'; size?: 'sm' | 'md' | 'lg'; state?: 'default' | 'hover' | 'active' | 'disabled' | 'loading'; }
// Variants matrix
const Button = ({ variant = 'primary', size = 'md', state = 'default', ...props }) => {
const variantClass = button--${variant};
const sizeClass = button--${size};
const stateClass = button--${state};
return (
<button className={button ${variantClass} ${sizeClass} ${stateClass}} {...props} />
);
};
// Usage <Button variant="primary" size="md" state="default">Primary</Button> <Button variant="secondary" size="lg" state="hover">Secondary Large</Button> <Button variant="danger" size="sm" state="disabled">Delete</Button>
Variant Documentation
Document all variants with examples:
Button Component
Variants
Variant: primary
- Default button style
- Used for primary actions
- Example: "Save", "Submit", "Create"
Variant: secondary
- Secondary button style
- Used for secondary actions
- Example: "Cancel", "Back", "Skip"
Variant: ghost
- Minimal button style
- Used for tertiary actions
- Example: "Learn More", "View Details"
Variant: danger
- Danger button style
- Used for destructive actions
- Example: "Delete", "Remove", "Discard"
Sizes
Size: sm
- 32px height
- 12px font size
- Used in compact spaces
Size: md
- 40px height
- 14px font size
- Default size
Size: lg
- 48px height
- 16px font size
- Used for prominent actions
States
State: default
- Normal appearance
State: hover
- Slightly darker or lighter
- Indicates interactivity
State: active
- Pressed appearance
- Indicates the button is being clicked
State: disabled
- Grayed out
- Cursor is not-allowed
- Not clickable
State: loading
- Shows spinner
- Indicates action in progress
- Not clickable
Component Documentation
What to Document
-
Purpose — What does this component do?
-
Props — What props does it accept?
-
Variants — What variants are available?
-
States — What states can it be in?
-
Examples — How do you use it?
-
Accessibility — What accessibility features does it have?
-
Edge Cases — What edge cases should you be aware of?
Documentation Template
Component Name
Purpose
Brief description of what this component does and when to use it.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'primary' | 'secondary' | 'primary' | Visual variant |
size | 'sm' | 'md' | 'lg' | 'md' | Component size |
disabled | boolean | false | Disable the component |
children | ReactNode | - | Component content |
Variants
Primary
Used for primary actions.
<Button variant="primary">Primary Action</Button>
Secondary
Used for secondary actions.
<Button variant="secondary">Secondary Action</Button>
States
Default
Normal appearance.
Disabled
Grayed out, not clickable.
<Button disabled>Disabled</Button>
Loading
Shows spinner, not clickable.
<Button loading>Loading...</Button>
Accessibility
- Keyboard accessible (Enter, Space to activate)
- Screen reader friendly (announces button text)
- Focus visible (outline on focus)
- Aria-label support for icon-only buttons
Examples
Basic Button
<Button onClick={() => alert('Clicked!')}>Click Me</Button>
With Icon
<Button icon={<SaveIcon />}>Save</Button>
Full Width
<Button fullWidth>Full Width Button</Button>
Edge Cases
- Icon-only buttons must have aria-label
- Disabled buttons should not be clickable
- Loading state should show spinner
- Very long text should wrap or truncate
## How to Use This Skill with Claude Code
### Audit Your Components
"I'm using the component-architecture skill. Can you audit my components?
- Identify components that violate single responsibility
- Suggest component composition improvements
- Check component documentation completeness
- Identify reusable patterns I'm missing
- Suggest component library structure"
### Design a Component System
"Can you help me design a component system?
- Define atomic components (atoms, molecules, organisms)
- Create component architecture
- Design component props interfaces
- Define variants for each component
- Create component documentation"
### Refactor Components
"Can you help me refactor my components?
- Break down complex components
- Improve component composition
- Simplify prop interfaces
- Add missing variants
- Improve documentation"
### Generate Component Library
"Can you generate a component library?
- Create all atomic components (Button, Input, Label, etc.)
- Create molecules (FormInput, SearchBar, etc.)
- Create organisms (Card, Modal, etc.)
- Include TypeScript types
- Include Tailwind CSS styling
- Include comprehensive documentation"
## Design Critique: Evaluating Your Components
Claude Code can critique your components:
"Can you evaluate my component architecture?
- Are my components following single responsibility?
- Is my component composition good?
- Are my prop interfaces well-designed?
- Is my documentation comprehensive?
- What's one thing I could improve immediately?"
## Integration with Other Skills
- **design-foundation** — Component tokens and styling
- **layout-system** — Component layout patterns
- **typography-system** — Component typography
- **color-system** — Component colors
- **accessibility-excellence** — Component accessibility
- **interaction-design** — Component interactions
## Key Principles
**1. Single Responsibility**
Each component should have one clear purpose.
**2. Composition Over Inheritance**
Build complex components by composing simpler ones.
**3. Props Interface Design**
Design props carefully for clarity and flexibility.
**4. Variants Enable Reusability**
Well-designed variants make components reusable across contexts.
**5. Documentation Enables Adoption**
Comprehensive documentation helps your team use components effectively.
## Checklist: Is Your Component Architecture Ready?
- [ ] Components follow single responsibility principle
- [ ] Components are composed from simpler components
- [ ] Props interfaces are well-designed and documented
- [ ] All variants are defined and documented
- [ ] All states are defined and documented
- [ ] Components are accessible (keyboard, screen reader, focus)
- [ ] Components have comprehensive documentation
- [ ] Component library is organized (atoms, molecules, organisms)
- [ ] Components are reusable across the product
- [ ] Components are tested (unit tests, visual tests)
A well-designed component architecture is the foundation of a scalable, maintainable product.