385 lines
14 KiB
Markdown
385 lines
14 KiB
Markdown
# Module 12: Functional Components
|
|
|
|
**Time: 45 min | Agent: Freya | Phase: Design | Focus: UX**
|
|
|
|
---
|
|
|
|
## From Pages to Patterns
|
|
|
|
You've specified your pages. You documented every element, every state, every interaction.
|
|
|
|
And now something happens.
|
|
|
|
You're writing the specification for your third page... and you notice you're describing the same button again. Same states. Same behavior. Same validation pattern.
|
|
|
|
**You're repeating yourself.**
|
|
|
|
This is good. This means patterns have emerged.
|
|
|
|
---
|
|
|
|
## What Are Functional Components?
|
|
|
|
Functional Components are the **reusable building blocks** of your interface.
|
|
|
|
Not colors. Not fonts. Not individual buttons.
|
|
|
|
**Widgets with functionality.**
|
|
|
|
```
|
|
NOT a component: IS a component:
|
|
- Blue (#0066FF) - Login Form (email, password, validation, submit)
|
|
- A single button - Search Widget (input, suggestions, keyboard nav)
|
|
- 16px font size - Comment Section (textarea, submit, character count)
|
|
- A margin value - Task Card (checkbox, title, status, actions)
|
|
```
|
|
|
|
**The difference:** Functional Components are widgets that DO something - they have behavior, validation, state management, and user interactions.
|
|
|
|
---
|
|
|
|
## Where You Are in WDS
|
|
|
|
```
|
|
Module 11: Conceptual Specifications
|
|
You wrote complete specifications for each page.
|
|
You documented every element in detail.
|
|
↓
|
|
Module 12: Functional Components ← YOU ARE HERE
|
|
You identify what's repeated across pages.
|
|
You extract patterns into reusable components.
|
|
↓
|
|
Module 13: Visual Design
|
|
You apply visual style to your components.
|
|
```
|
|
|
|
**This module is the bridge** between detailed specifications and actual design system.
|
|
|
|
---
|
|
|
|
## Why This Matters
|
|
|
|
When you specify pages across your app, you might write the same widget specification multiple times.
|
|
|
|
- Homepage: "Weather widget: location, current temp, 5-day forecast, icons..."
|
|
- Dashboard: "Weather widget: location, current temp, 5-day forecast, icons..."
|
|
- User profile: "Weather widget: location, current temp, 5-day forecast, icons..."
|
|
|
|
**That's inefficient.** And when something changes (like adding hourly forecast), you update multiple places.
|
|
|
|
Instead, you extract the pattern:
|
|
|
|
- **Component:** Weather Widget (defined once with all variants, data sources, states)
|
|
- **Page specs:** "Use Weather Widget (compact variant)"
|
|
|
|
**Define once. Reference everywhere. Change once. Update everywhere.**
|
|
|
|
### How Functional Components Connect Pages
|
|
|
|
```
|
|
PAGE COMPONENT PAGE
|
|
┌──────────────────┐ ┌────────────────────┐ ┌──────────────────┐
|
|
│ P01: Homepage │ │ WEATHER │ │ P04: Dashboard │
|
|
├──────────────────┤ │ WIDGET │ ├──────────────────┤
|
|
│ │ ├────────────────────┤ │ │
|
|
│ Hero Section: │ │ Data: │ │ Sidebar: │
|
|
│ - Component: │◄──┤ • Current temp │──►│ - Component: │
|
|
│ WeatherWidget │ │ • Conditions │ │ WeatherWidget │
|
|
│ (detailed) │ │ • Location │ │ (compact) │
|
|
│ - Location: │ │ • 5-day forecast │ │ - Location: │
|
|
│ User's city │ │ • Hourly (opt.) │ │ Auto-detect │
|
|
│ │ │ │ │ │
|
|
│ │ │ Variants: │ │ │
|
|
│ │ │ • compact │ │ │
|
|
│ │ │ • detailed │ │ │
|
|
│ │ │ • minimal │ │ │
|
|
│ │ │ │ │ │
|
|
│ │ │ States: │ │ │
|
|
│ │ │ • loading │ │ │
|
|
│ │ │ • loaded │ │ │
|
|
│ │ │ • error │ │ │
|
|
│ │ │ • refreshing │ │ │
|
|
└──────────────────┘ └────────────────────┘ └──────────────────┘
|
|
│
|
|
▼
|
|
INTEGRATION
|
|
┌──────────────────────────────────────────────────────────────────┐
|
|
│ When homepage renders hero weather widget: │
|
|
│ │
|
|
│ 1. Reads: Component = WeatherWidget (detailed) │
|
|
│ 2. Looks up: WeatherWidget definition │
|
|
│ 3. Applies: Detailed variant (current + 5-day + hourly) │
|
|
│ 4. Configures: Location = User's city │
|
|
│ 5. Inherits: All states, API integration, refresh logic │
|
|
│ 6. Renders: Full weather display with forecast │
|
|
│ │
|
|
│ Result: Fully-functional weather widget with detailed view │
|
|
└──────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**The structure:** Multiple pages reference one widget. Change the widget definition, all instances update.
|
|
|
|
---
|
|
|
|
## What Happens in This Module
|
|
|
|
You'll learn to:
|
|
|
|
1. **Identify patterns** — Spot elements that appear 2+ times
|
|
2. **Decide what to extract** — Not everything should be a component
|
|
3. **Document components** — Create reusable definitions
|
|
4. **Update page specs** — Reference components instead of repeating specs
|
|
|
|
By the end, your specifications become **modular and maintainable**.
|
|
|
|
---
|
|
|
|
## Why Extract Components?
|
|
|
|
### Consistency
|
|
|
|
Same component = same behavior everywhere.
|
|
|
|
### Efficiency
|
|
|
|
Specify once, reference many times.
|
|
|
|
### Maintainability
|
|
|
|
Change once, update everywhere.
|
|
|
|
### Communication
|
|
|
|
Shared vocabulary with developers.
|
|
|
|
---
|
|
|
|
## When to Extract
|
|
|
|
A pattern becomes a component when:
|
|
|
|
- **Appears 2+ times** — More than once signals a pattern worth extracting
|
|
- **Consistent behavior** — Same interactions everywhere
|
|
- **Worth centralizing** — Benefits from single definition
|
|
- **Meaningful abstraction** — Not just "box with text"
|
|
|
|
---
|
|
|
|
## Component Anatomy
|
|
|
|
```markdown
|
|
## Search Widget
|
|
|
|
### Description
|
|
Reusable search interface with input, suggestions, and keyboard navigation.
|
|
Used in header navigation, content libraries, and admin panels.
|
|
|
|
### Variants
|
|
| Variant | Use Case |
|
|
|---------|----------|
|
|
| Global | Site-wide search (all content types) |
|
|
| Scoped | Category-specific search |
|
|
| Instant | Real-time filtering (no submit) |
|
|
|
|
### States
|
|
- Empty (placeholder visible)
|
|
- Typing (suggestions appear)
|
|
- Loading (fetching results)
|
|
- Results (dropdown with matches)
|
|
- No Results (helpful message)
|
|
- Selected (item chosen from suggestions)
|
|
- Error (API failure)
|
|
|
|
### Props
|
|
| Prop | Type | Default | Description |
|
|
|------|------|---------|-------------|
|
|
| variant | string | global | Search scope |
|
|
| placeholder | string | "Search..." | Input placeholder |
|
|
| minChars | number | 3 | Min chars before search |
|
|
| debounce | number | 300 | Delay before API call (ms) |
|
|
| maxResults | number | 10 | Max suggestions shown |
|
|
| onSelect | function | - | Callback when item selected |
|
|
|
|
### Usage Rules
|
|
- Search triggers after 3 characters typed
|
|
- Shows max 10 suggestions
|
|
- Escape key clears and closes
|
|
- Enter selects first result
|
|
- Click outside closes suggestions
|
|
|
|
### Accessibility
|
|
- Role: combobox
|
|
- Keyboard: Arrow keys navigate, Enter selects, Escape closes
|
|
- Screen reader announces result count
|
|
- aria-autocomplete="list"
|
|
- aria-expanded when suggestions visible
|
|
```
|
|
|
|
---
|
|
|
|
## The Freya Method
|
|
|
|
Freya notices patterns as you specify:
|
|
|
|
> "This is the third time you've specified a search widget with autocomplete. Should we extract it as a component?"
|
|
|
|
> "Your comment forms have different validation rules — should we standardize?"
|
|
|
|
She helps you see what's becoming a pattern.
|
|
|
|
---
|
|
|
|
## Component vs. Instance
|
|
|
|
**Component:** The widget definition (Search Widget)
|
|
**Instance:** A specific usage (header-global-search)
|
|
|
|
In your specs:
|
|
- Define components in your Design System
|
|
- Reference components in your page specs
|
|
|
|
```markdown
|
|
### Global Search
|
|
- Component: Search Widget (global)
|
|
- Placeholder: "Search documentation..."
|
|
- OnSelect: Navigate to selected page
|
|
```
|
|
|
|
### How Integration Works
|
|
|
|
```
|
|
COMPONENT DEFINITION (C-UX-Scenarios/Functional-Components/search-widget.md)
|
|
┌────────────────────────────────────────────────────────────┐
|
|
│ Search Widget │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ Variants: │
|
|
│ - global: All content types │
|
|
│ - scoped: Category-specific │
|
|
│ - instant: Real-time filtering │
|
|
│ │
|
|
│ States: │
|
|
│ - empty, typing, loading, results, no-results, error │
|
|
│ │
|
|
│ Props: │
|
|
│ - variant (global|scoped|instant) │
|
|
│ - placeholder (string) │
|
|
│ - minChars (number, default: 3) │
|
|
│ - onSelect (function) │
|
|
└────────────────────────────────────────────────────────────┘
|
|
↓
|
|
INHERITS ALL PROPERTIES
|
|
↓
|
|
┌────────────────────────────────────────────────────────────┐
|
|
│ INSTANCE (P01-homepage/specification.md) │
|
|
├────────────────────────────────────────────────────────────┤
|
|
│ header-global-search: │
|
|
│ - Component: Search Widget ← References def │
|
|
│ - variant: global ← Selects variant │
|
|
│ - placeholder: "Search docs..." ← Instance-specific │
|
|
│ - onSelect: Navigate to page ← Instance-specific │
|
|
│ │
|
|
│ INHERITS FROM COMPONENT: │
|
|
│ ✓ All global variant behavior (searches all content) │
|
|
│ ✓ All states (typing, loading, results, errors...) │
|
|
│ ✓ All accessibility (keyboard nav, screen reader...) │
|
|
│ ✓ All usage rules (min 3 chars, debounce, max results) │
|
|
└────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**The power:** Change the Search Widget once, all instances update everywhere.
|
|
|
|
---
|
|
|
|
## Not Everything Is a Component
|
|
|
|
Some things are just styled elements:
|
|
|
|
| Component | Not a Component |
|
|
|-----------|-----------------|
|
|
| Button | A specific color |
|
|
| Card | A specific margin |
|
|
| Input | A single label |
|
|
| Modal | A page layout |
|
|
|
|
Components have behavior. Styles have appearance.
|
|
|
|
---
|
|
|
|
## Output
|
|
|
|
Functional Components documented:
|
|
|
|
```
|
|
C-UX-Scenarios/
|
|
└── Functional-Components/
|
|
├── weather-widget.md
|
|
├── search-widget.md
|
|
├── login-form.md
|
|
└── task-card.md
|
|
```
|
|
|
|
**Location:** Functional Components live in the UX Scenarios folder, separate from the Design System (which handles visual styling only).
|
|
|
|
---
|
|
|
|
## Design System
|
|
|
|
| Mode | Component Handling |
|
|
|------|-------------------|
|
|
| **None** | Inline in page specs |
|
|
| **Building** | Extract to C-UX-Scenarios/Functional-Components/ |
|
|
| **Library** | Reference external (shadcn, etc.) |
|
|
| **Existing** | Import from previous project |
|
|
|
|
---
|
|
|
|
## Common Mistakes
|
|
|
|
| Mistake | Fix |
|
|
|---------|-----|
|
|
| Extracting too early | Wait for 2+ usages |
|
|
| Too specific | Keep components generic |
|
|
| Too generic | Must have clear purpose |
|
|
| Missing states | Document all states |
|
|
| Inconsistent naming | Use clear conventions |
|
|
|
|
---
|
|
|
|
## Practice
|
|
|
|
Review your specifications from Module 11:
|
|
|
|
1. Identify repeated patterns
|
|
2. List elements that appear 2+ times
|
|
3. Document one as a component
|
|
4. Update specs to reference it
|
|
|
|
---
|
|
|
|
## Lessons
|
|
|
|
### [Lesson 1: When Patterns Emerge](lesson-01-patterns-emerge.md)
|
|
Identifying reusable elements across your specifications
|
|
|
|
### [Lesson 2: Functional Component Anatomy](lesson-02-component-anatomy.md)
|
|
How to document Functional Components completely
|
|
|
|
---
|
|
|
|
## Tutorial
|
|
|
|
### [Tutorial 12: Extract Your Components](tutorial-12.md)
|
|
Hands-on guide to identifying and documenting reusable patterns
|
|
|
|
---
|
|
|
|
## Next Module
|
|
|
|
**[Module 13: Design System →](../module-13-design-system/module-13-design-system-overview.md)**
|
|
|
|
Choose your design system approach.
|
|
|
|
---
|
|
|
|
*Part of the WDS Course: From Designer to Linchpin*
|