Building Reusable UI Components
Lesson 37 โข Advanced Track
What You'll Learn
- Build a complete button system with variants, sizes, and states
- Create cards with headers, footers, images, and interactive styles
- Design form inputs with validation states, selects, checkboxes, and toggles
- Build tags/badges, avatar components, and alert banners
- Use CSS variables for component-level customisation
๐ก Real-World Analogy
Reusable components are like LEGO bricks. A 2ร4 brick (button) can be red, blue, or green (variants) and small or large (sizes). You build each brick type once, then snap them together into any structure without creating new bricks each time.
Designing Component Systems
A component system follows a consistent pattern: base class (shared structure) + modifier classes (visual variants). The base class handles layout, sizing, and spacing. Modifiers change colours, borders, and other visual properties without duplicating structural CSS.
CSS variables make components customisable โ consumers can override --primary or --radius without editing the component stylesheet.
Component Design Patterns
| Pattern | Example | Purpose |
|---|---|---|
| Base + Variant | .btn .btn-primary | Colour/style variations |
| Base + Size | .btn .btn-sm | Size variations |
| Compound | .card .card-header .card-body | Multi-part component |
| State | .form-input--error | Validation/interaction states |
| Composition | .btn-primary .btn-sm | Combine variant + size |
1. Button System
<!DOCTYPE html>
<html><head><style>
:root { --primary: #1976D2; --primary-hover: #1565C0; --danger: #D32F2F; --danger-hover: #B71C1C; --success: #2E7D32; --success-hover: #1B5E20; --radius: 8px; }
body { font-family: system-ui, sans-serif; padding: 24px; }
h2 { color: #1565C0; }
.btn { display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; border: none; border-radius: var(--radius); font-weight: 600; cursor: pointer; transition: all 0.2s; font-size: 0.95rem; text-decoration: no
...2. Card System
<!DOCTYPE html>
<html><head><style>
:root { --surface: #fff; --border: #e0e0e0; --text: #1a1a1a; --muted: #757575; --primary: #1976D2; --radius: 12px; --shadow: 0 2px 8px rgba(0,0,0,0.08); }
body { font-family: system-ui, sans-serif; padding: 24px; background: #fafafa; }
h2 { color: #1565C0; }
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; box-shadow: var(--shadow); }
.card-header { padding: 16px 20px; border-bottom: 1px solid
... Compound components: Cards use a multi-part pattern: .card (wrapper), .card-header, .card-body, .card-footer. Each part is optional โ a card can have just a body, or all four parts. This flexibility makes the component work in many contexts.
3. Form Components
<!DOCTYPE html>
<html><head><style>
:root { --primary: #1976D2; --border: #ddd; --radius: 8px; --danger: #D32F2F; --success: #2E7D32; }
body { font-family: system-ui, sans-serif; padding: 24px; max-width: 500px; }
h2 { color: #1565C0; }
.form-group { margin-bottom: 20px; }
.form-label { display: block; font-weight: 600; margin-bottom: 6px; font-size: 0.9rem; }
.form-input { width: 100%; padding: 10px 14px; border: 2px solid var(--border); border-radius: var(--radius); font-size: 1rem; box-sizing
...4. Tags, Avatars & Alerts
<!DOCTYPE html>
<html><head><style>
:root { --primary: #1976D2; --danger: #D32F2F; --success: #2E7D32; --warning: #E65100; }
body { font-family: system-ui, sans-serif; padding: 24px; }
h2 { color: #1565C0; }
/* Tags */
.tag { display: inline-flex; align-items: center; gap: 4px; padding: 4px 12px; border-radius: 99px; font-size: 0.8rem; font-weight: 600; }
.tag-blue { background: #E3F2FD; color: var(--primary); }
.tag-green { background: #E8F5E9; color: var(--success); }
.tag-red { background: #F
...When to Use This
- Design systems: Build your own "Bootstrap" for consistent UI across a project
- Team projects: Shared components prevent each developer creating their own button style
- Prototyping: Pre-built components let you assemble pages rapidly
- Client projects: Customise via CSS variables without rewriting component code
Common Mistakes
- Styling with IDs โ IDs have high specificity and can't be reused. Always use classes for components.
- Hardcoding colours โ Use CSS variables so themes can override component colours.
background: var(--primary)notbackground: #1976D2. - Too many responsibilities โ A button shouldn't handle layout. Keep components single-purpose.
- Not testing disabled/error states โ Components need to look good in all states, not just the default happy path.
- Inconsistent spacing scales โ Use a spacing system (4px, 8px, 12px, 16px, 24px, 32px) instead of random values.
- Forgetting focus styles โ Every interactive component needs a visible focus indicator for keyboard users.
๐ Lesson Complete
- โ Base class + modifier classes = flexible component variants
- โ CSS variables enable runtime customisation per-instance
- โ Size variants (sm, md, lg) use consistent spacing scales
- โ Compound components (card-header, card-body, card-footer) are optional and flexible
- โ Form inputs need error, success, and disabled states built in
- โ Toggle switches use checkbox + label + CSS for pure HTML/CSS implementation
- โ Avatar groups use negative margins for overlapping effect
- โ Compose components: cards contain buttons, badges, avatars, and inputs
Sign up for free to track which lessons you've completed and get learning reminders.