React Composition Patterns
Composition patterns for building flexible, maintainable React components. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. Upstream: composition-patterns in vercel-labs/agent-skills.
Scope
- Applies to: reusable component APIs, compound components, explicit variants, React 19 ref/
use()changes - Does NOT cover: visual direction (frontend-design-v1); Next.js caching or RSC data fetching (next-v16, vercel-react-v1)
Assumptions
- React 19+ in typical Basilic apps; skip the React 19 rule section on React 18
- Server/client boundaries already exist; composition must not move server data into client-only providers
Principles
- Prefer composition over boolean configuration for reused components
- Lift client UI state only when siblings need it; keep server data on the server
- Extract shared primitives after a second call site, not for one-off route UI
Constraints
MUST
- Extract compound components only for a shared UI package or 2+ call sites, not a single route leaf
- Keep React Server Components fetching their own data; pass server-rendered children into client leaves instead of lifting that data into a client provider
- Leave URL-shareable state, async server state, and grouped local UI state on the libraries the project already uses (query-string parsers, TanStack Query, grouped-state hooks)—do not replace them with a generic context DI layer
SHOULD
- Skip
forwardRefunless a parent must attach a ref - Use explicit variant components instead of
isXboolean modes on reused APIs - Prefer
childrenoverrenderXprops
AVOID
- Premature abstractions around a one-off screen
- Client providers whose only job is to re-export RSC-fetched props
- Breaking existing
'use client'placement to “compose” everything
Interactions
- App Router / RSC: next-v16
- React performance: vercel-react-v1
- shadcn primitives: shadcn-v3
- URL state: nuqs-v2
- Client async: tanstack-query-v5
- Grouped local state: ahooks-v3
When to apply
- Refactoring components with many boolean props
- Building reusable component libraries
- Designing flexible component APIs
- Reviewing component architecture
- Working with compound components or context providers
Rule categories by priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Component Architecture | HIGH | architecture- |
| 2 | State Management | MEDIUM | state- |
| 3 | Implementation Patterns | MEDIUM | patterns- |
| 4 | React 19 APIs | MEDIUM | react19- |
Quick reference
1. Component Architecture (HIGH)
architecture-avoid-boolean-props— Don't add boolean props to customize behavior; use compositionarchitecture-compound-components— Structure complex components with shared context
2. State Management (MEDIUM)
state-decouple-implementation— Provider is the only place that knows how state is managedstate-context-interface— Define generic interface with state, actions, meta for dependency injectionstate-lift-state— Move state into provider components for sibling access
Apply these only where the Constraints above allow. Do not lift server-owned data.
3. Implementation Patterns (MEDIUM)
patterns-explicit-variants— Create explicit variant components instead of boolean modespatterns-children-over-render-props— Use children for composition instead of renderX props
4. React 19 APIs (MEDIUM)
React 19+ only. Skip this section on React 18 or earlier.
react19-no-forwardref— Don't useforwardReffor new components.use()is optional for conditional context reads;useContext()remains supported.
How to use
Read individual rule files for detailed explanations and code examples:
rules/architecture-avoid-boolean-props.md
rules/state-context-interface.md
Each rule file contains why it matters, incorrect and correct examples, and extra context.
Full compiled guide (do not name this AGENTS.md; Cursor always-loads that filename): references/compiled.md