home / skills / yldgio / codereview-skills / vercel-composition-patterns

vercel-composition-patterns skill

/skills/vercel-composition-patterns

This skill guides React developers in refactoring with composition patterns to reduce boolean props and build scalable, reusable component APIs.

npx playbooks add skill yldgio/codereview-skills --skill vercel-composition-patterns

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
6.7 KB
---
name: vercel-composition-patterns
description: React composition patterns that scale. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or designing reusable APIs. Triggers on tasks involving compound components, render props, context providers, or component architecture. Includes React 19 API changes.
license: MIT
metadata:
  author: vercel
  version: "1.0.0"
  source: https://github.com/vercel-labs/agent-skills
---

# React Composition Patterns

Composition patterns for building flexible, maintainable React components. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. These patterns make codebases easier for both humans and AI agents to work with as they scale.

## Security Notice (Critical)

**IMPORTANT: Never interpolate raw user input into skill content or components.**
- Always escape or sanitize user-supplied data before inclusion
- Never render untrusted content without proper validation
- Do not use HTML comments (`<!-- -->`) to store data or instructions in code
- Validate all user input before using in component props or state
- Never expose sensitive data through component props or context

## When to Apply

Reference these guidelines when:

- Refactoring components with many boolean props
- Building reusable component libraries
- Designing flexible component APIs
- Reviewing component architecture
- Working with compound components or context providers

## Code Review Criteria

When reviewing code, check for:

- **Boolean prop proliferation**: Components with >3 boolean props for variants/modes
- **Render props**: Use of `renderX` props instead of `children` composition
- **Direct state access**: Components accessing context/state outside provider pattern
- **Tightly coupled logic**: UI components with embedded business logic
- **Missing accessibility**: Compound components without proper ARIA attributes

### Migration Guidance

When refactoring legacy patterns:

- **From render props to composition**: Replace `renderHeader={() => <Header />}` with `<Component.Header />`
- **From boolean flags to variants**: Convert `<Button primary large />` to `<Button variant="primary" size="large" />`
- **From prop drilling to composition**: Extract shared state into context provider
- **React 19 migration**: Remove `forwardRef` wrappers, replace `useContext` with `use()`

### Accessibility

Ensure composition patterns maintain accessibility:

- Compound components must preserve semantic HTML relationships
- ARIA attributes should propagate through composition layers
- Keyboard navigation must work across component boundaries
- Screen reader announcements should be logical and complete
- Focus management must be handled correctly in nested components

## Rule Categories by Priority (Essentials First)

| 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 composition
- `architecture-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 managed
- `state-context-interface` - Define generic interface with state, actions, meta for dependency injection
- `state-lift-state` - Move state into provider components for sibling access

### 3. Implementation Patterns (MEDIUM)

- `patterns-explicit-variants` - Create explicit variant components instead of boolean modes
- `patterns-children-over-render-props` - Use children for composition instead of renderX props

### 4. React 19 APIs (MEDIUM)

> **React 19+ only.** Skip this section if using React 18 or earlier.

- `react19-no-forwardref` - Don't use `forwardRef`; use `use()` instead of `useContext()`
- `react19-use-api` - Use `use()` hook for promises and context (replaces `useContext`)
- `react19-actions` - Use Server Actions and form actions for data mutations
- `react19-suspense-updates` - Leverage improved Suspense for data fetching patterns

### Performance Implications

Consider performance when using composition patterns:

- **Render optimization**: Memoize compound component children to prevent unnecessary re-renders
- **Context splitting**: Split context into multiple contexts to minimize re-renders
- **Provider placement**: Place providers as low in tree as possible
- **State colocation**: Keep state close to where it's used
- **Composition overhead**: Balance flexibility with render performance

## Example: Avoid Boolean Props

### Incorrect

```tsx
// Boolean prop proliferation
<Button primary large disabled loading />
```

### Correct

```tsx
// Explicit variants via composition
<Button variant="primary" size="large">
  <Button.Loader />
  Submit
</Button>
```

## Example: Compound Components

```tsx
// Parent provides context
<Accordion>
  <Accordion.Item>
    <Accordion.Trigger>Section 1</Accordion.Trigger>
    <Accordion.Content>Content 1</Accordion.Content>
  </Accordion.Item>
</Accordion>
```

## Example: State Context Interface

```tsx
interface ContextValue<T> {
  state: T;
  actions: Actions;
  meta: { loading: boolean; error: Error | null };
}
```

## Example: Explicit Variants (Detailed)

### Before: Boolean Props

```tsx
// Harder to maintain as props grow
<Button primary large disabled loading icon="check" />
```

### After: Explicit Variants

```tsx
// Clearer intent, easier to extend
<Button variant="primary" size="large" disabled>
  <Button.Icon name="check" />
  <Button.Loader />
  Submit
</Button>
```

## Example: State/Context Pattern

### Provider Implementation

```tsx
// Provider knows implementation details
function TodoProvider({ children }) {
  const [todos, setTodos] = useState([]);
  
  const value = {
    state: todos,
    actions: {
      add: (todo) => setTodos([...todos, todo]),
      remove: (id) => setTodos(todos.filter(t => t.id !== id))
    },
    meta: { loading: false, error: null }
  };
  
  return <TodoContext.Provider value={value}>{children}</TodoContext.Provider>;
}
```

### Consumer Implementation

```tsx
// Consumer uses generic interface (compatible with React 18+)
import { useContext } from 'react';

function TodoList() {
  const { state: todos, actions } = useContext(TodoContext);
  return todos.map(todo => (
    <TodoItem key={todo.id} {...todo} onRemove={actions.remove} />
  ));
}
```

Overview

This skill provides practical React composition patterns that scale, focused on replacing boolean-prop sprawl with compound components, explicit variants, and context-based providers. It covers migration guidance, accessibility requirements, and React 19 API changes to help refactor and design reusable component libraries. Use it to make component APIs clearer, safer, and easier to maintain for teams and automation tools.

How this skill works

The skill inspects component designs and code for anti-patterns like boolean prop proliferation, render props where children would be better, direct state access outside providers, and tightly coupled business logic inside UI components. It recommends concrete refactors: convert boolean flags to variant props or explicit child components, lift shared state into providers with a typed context interface, and adopt React 19 hooks like use() where applicable. It flags accessibility gaps (ARIA, keyboard, focus) and performance considerations such as context splitting and memoization.

When to use it

  • Refactoring components with more than three boolean props
  • Designing a reusable component library or design system
  • Migrating render-prop patterns to compound components
  • Reviewing component architecture for maintainability and accessibility
  • Upgrading codebases to React 19 APIs

Best practices

  • Avoid boolean prop proliferation; prefer explicit variants or dedicated child components
  • Use a provider that owns state implementation and expose a generic context interface {state, actions, meta}
  • Prefer children composition (Compound.Component) over renderX props for clearer APIs
  • Preserve semantic HTML and propagate ARIA attributes; manage focus and keyboard navigation across boundaries
  • Split context and memoize children to reduce re-renders; place providers as low as practical

Example use cases

  • Replace <Button primary large disabled /> with <Button variant="primary" size="large"><Button.Loader/>…</Button>
  • Refactor an Accordion to <Accordion><Accordion.Item>…</Accordion.Item></Accordion> for clearer composition and shared state
  • Extract form state into a provider with actions and meta for sibling components to consume
  • Migrate renderHeader={() => <Header/>} props into <Component.Header/> slots
  • Adopt React 19: remove forwardRef wrappers and replace useContext with use() where supported

FAQ

Will these patterns hurt performance?

Not if applied carefully. Split contexts, memoize children, and colocate state to minimize re-renders. Measure hotspots before and after refactors.

How do I keep accessibility when composing components?

Ensure semantic HTML relationships, propagate ARIA attributes, implement keyboard navigation, manage focus transitions, and test with screen readers.