Audience: Teams aligning with Frontend / web engineering body of knowledge and Frontend patterns (blueprint).
Overview
In modern frontends, a component is a reusable boundary that encapsulates markup, behavior, and (optionally) styling. Composition—how components nest and communicate—determines scalability, testability, and design-system fit more than any single framework feature.
Component taxonomy
| Axis |
Category |
Role |
Typical signals |
| Data vs presentation |
Presentational |
Renders UI from props; minimal logic |
No stores, no side effects beyond display |
|
Container |
Loads data, wires callbacks, passes props |
Connects to APIs, router, global state |
| Behavior |
Smart |
Knows how to fetch/transform/coordinate |
Hooks, services, context consumers |
|
Dumb |
Knows only what to render from inputs |
Pure render from props/slots |
| Atomic Design |
Atom |
Smallest UI unit (button, label, icon) |
No business meaning |
|
Molecule |
Simple group of atoms (search field + button) |
Single local concern |
|
Organism |
Distinct section (header, product card) |
May compose molecules and atoms |
|
Template |
Page-level layout without real content |
Structure and regions |
|
Page |
Template + real data |
Route-level instance |
Composition patterns
| Pattern |
Example use case |
Pros |
Cons |
| Children / slots |
Layout shell with arbitrary main content |
Maximum flexibility; matches platform idioms |
Harder to document “allowed” children |
| Render props |
List that delegates row rendering |
Full control at call site |
Verbose; nesting can hurt readability |
| Higher-order components (HOC) |
Inject auth, analytics, or theming |
Cross-cutting reuse without changing tree shape |
Indirection; display names; ref forwarding |
| Hooks / composables |
Shared pagination, keyboard shortcuts |
Colocated logic; tree stays flat |
Rules of hooks; not a visual component API |
| Compound components |
Tabs, dialogs, menus with coordinated state |
Encapsulated implicit state; ergonomic API |
Requires clear context/subcomponent docs |
Component API design principles
| Principle |
Practice |
| Props contract |
Prefer small, named props; use discriminated unions for variants; document required vs optional clearly. |
| Events / callbacks |
Name by user intent (onSubmit) not implementation; keep arity stable; avoid leaking raw DOM unless intentional. |
| Slots / children |
Default slot for primary content; named slots for chrome (header, footer) when the framework supports it. |
| Defaults |
Sensible defaults reduce configuration; document overrides in Storybook or equivalent. |
State ownership patterns
| Pattern |
When |
Trade-off |
| Local state |
UI-only ephemeral state (open/closed, draft input) |
Simple; invisible to siblings |
| Lifted state |
Siblings need the same value |
Clear data flow; can cause prop drilling |
| Context / provide-inject |
Many descendants need theme, locale, auth shell |
Avoids drilling; easy to overuse |
| External store |
Cross-cutting app state with clear update rules |
Predictable updates; adds global mental model |
Design system integration
| Concern |
Guidance |
| Tokens |
Map design tokens (color, space, type) to component props or CSS variables; avoid magic numbers in components. |
| Theming |
Prefer token-driven themes over one-off overrides; document contrast and modes (light/dark/high-contrast). |
| Variants |
Encode visual/behavior variants in a small matrix (e.g. size × variant); avoid boolean prop explosion. |
| Documentation |
Storybook (or equivalent) for states, a11y notes, and composition examples—not only happy path. |
Testing component architecture
| Layer |
Focus |
Examples |
| Unit (isolated) |
Props in → render/assert; hooks/composables in isolation |
Testing Library, component harness |
| Integration (composed) |
Parent + children + router/context stubs |
User-centric queries, realistic trees |
| Visual regression |
Pixel/story snapshots for design drift |
Chromatic, Percy, Loki |
| Accessibility |
Roles, labels, keyboard, focus |
axe, manual keyboard passes |
Framework comparison (component model)
| Framework |
Component shape |
Reuse mechanism |
Notable traits |
| React |
JSX + function/class components |
Hooks, HOCs, render props |
Explicit rerenders; large ecosystem |
| Vue |
SFC + Composition API / Options |
Composables, slots |
Reactivity built-in; templates optional |
| Svelte |
.svelte files, compiled |
Stores, snippets (v5+) |
Compile-time optimizations; less runtime |
| Angular |
Decorators, modules/standalone |
DI, directives |
Strong structure; enterprise defaults |
Anti-patterns
| Anti-pattern |
Why it hurts |
Mitigation |
| Prop drilling hell |
Every intermediate component knows unrelated props |
Context, composition, or colocated state |
| God components |
One file does data, layout, and business rules |
Split container/presentational; extract hooks |
| Premature abstraction |
Third use case imagined, not observed |
Wait for two real call sites; extract then |
| Breaking composition |
Internal structure exposed or fixed |
Stable public API; slots over fixed children |
Server vs client component boundaries
Align public component APIs with where work runs. Server-first frameworks (e.g. React Server Components, meta-frameworks) reward components that fetch on the server and pass serializable props to small client islands.
| Boundary |
Responsibility |
Client bundle impact |
| Server component / island |
Data fetch, heavy markdown, static structure |
None or minimal for that subtree |
| Client component |
Interactivity, browser APIs, subscriptions |
Pays parse/hydration cost |
Document which components are safe to import into client trees versus server-only modules.
Accessibility as part of the component API
Treat a11y as contract, not polish: consumers should not have to guess labels and keyboard behavior.
| Concern |
Component API implication |
| Keyboard |
Document focus order, roving tabindex if used, shortcut conflicts |
| Focus |
Expose ref or focus helpers for dialogs, traps, and return focus |
| ARIA |
Prefer composition patterns that set role, aria-*, and labelled-by consistently |
| Reduced motion |
Respect prefers-reduced-motion in motion variants |
External references
Keep project-specific performance budgets in docs/development/ and optimization decisions in docs/adr/, not in this file.