react-composition-patterns

7 stars

Best use case

react-composition-patterns is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Teams using react-composition-patterns should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/composition-patterns/SKILL.md --create-dirs "https://raw.githubusercontent.com/wpank/ai/main/skills/frontend/composition-patterns/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/composition-patterns/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How react-composition-patterns Compares

Feature / Agentreact-composition-patternsStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

This skill provides specific capabilities for your AI agent. See the About section for full details.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# React Composition Patterns

Build flexible, maintainable React components using compound components, context providers, and explicit variants. Avoid boolean prop proliferation.

## WHAT

Composition patterns that scale:
- Compound components with shared context
- State/actions/meta context interface for dependency injection
- Explicit variant components over boolean props
- Lifted state in provider components
- Children composition over render props

## WHEN

- Refactoring components with many boolean props
- Building reusable component libraries
- Designing flexible component APIs
- Creating compound components (Card, Dialog, Form, etc.)
- Components need shared state across sibling elements

## KEYWORDS

composition, compound components, context, provider, boolean props, variants, react patterns, component architecture, render props, children

**Source:** Vercel Engineering


## Installation

### OpenClaw / Moltbot / Clawbot

```bash
npx clawhub@latest install composition-patterns
```


---

## Core Principle

**Avoid boolean prop proliferation.** Each boolean doubles possible states.

```tsx
// BAD: 4 booleans = 16 possible states
<Composer isThread isDMThread isEditing isForwarding />

// GOOD: Explicit variants, clear intent
<ThreadComposer channelId="abc" />
<EditComposer messageId="xyz" />
```

---

## Pattern 1: Compound Components

Structure complex components with shared context. Consumers compose what they need.

```tsx
const ComposerContext = createContext<ComposerContextValue | null>(null)

// Provider handles state
function ComposerProvider({ children, state, actions, meta }: ProviderProps) {
  return (
    <ComposerContext value={{ state, actions, meta }}>
      {children}
    </ComposerContext>
  )
}

// Subcomponents access context
function ComposerInput() {
  const { state, actions: { update }, meta: { inputRef } } = use(ComposerContext)
  return (
    <TextInput
      ref={inputRef}
      value={state.input}
      onChangeText={(text) => update(s => ({ ...s, input: text }))}
    />
  )
}

function ComposerSubmit() {
  const { actions: { submit } } = use(ComposerContext)
  return <Button onPress={submit}>Send</Button>
}

// Export as namespace
const Composer = {
  Provider: ComposerProvider,
  Frame: ComposerFrame,
  Input: ComposerInput,
  Submit: ComposerSubmit,
  Header: ComposerHeader,
  Footer: ComposerFooter,
}
```

**Usage:**

```tsx
<Composer.Provider state={state} actions={actions} meta={meta}>
  <Composer.Frame>
    <Composer.Header />
    <Composer.Input />
    <Composer.Footer>
      <Composer.Formatting />
      <Composer.Submit />
    </Composer.Footer>
  </Composer.Frame>
</Composer.Provider>
```

---

## Pattern 2: Generic Context Interface

Define a contract any provider can implement: `state`, `actions`, `meta`.

```tsx
interface ComposerState {
  input: string
  attachments: Attachment[]
  isSubmitting: boolean
}

interface ComposerActions {
  update: (updater: (state: ComposerState) => ComposerState) => void
  submit: () => void
}

interface ComposerMeta {
  inputRef: React.RefObject<TextInput>
}

interface ComposerContextValue {
  state: ComposerState
  actions: ComposerActions
  meta: ComposerMeta
}
```

**Same UI, different providers:**

```tsx
// Local state provider
function ForwardMessageProvider({ children }) {
  const [state, setState] = useState(initialState)
  return (
    <ComposerContext value={{
      state,
      actions: { update: setState, submit: useForwardMessage() },
      meta: { inputRef: useRef(null) },
    }}>
      {children}
    </ComposerContext>
  )
}

// Global synced state provider  
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  return (
    <ComposerContext value={{
      state,
      actions: { update, submit },
      meta: { inputRef: useRef(null) },
    }}>
      {children}
    </ComposerContext>
  )
}
```

Both work with the same `<Composer.Input />` component.

---

## Pattern 3: Explicit Variants

Create named components for each use case instead of boolean modes.

```tsx
// BAD: What does this render?
<Composer
  isThread
  isEditing={false}
  channelId="abc"
  showAttachments
/>

// GOOD: Self-documenting
<ThreadComposer channelId="abc" />
```

**Implementation:**

```tsx
function ThreadComposer({ channelId }: { channelId: string }) {
  return (
    <ThreadProvider channelId={channelId}>
      <Composer.Frame>
        <Composer.Input />
        <AlsoSendToChannelField channelId={channelId} />
        <Composer.Footer>
          <Composer.Formatting />
          <Composer.Submit />
        </Composer.Footer>
      </Composer.Frame>
    </ThreadProvider>
  )
}

function EditComposer({ messageId }: { messageId: string }) {
  return (
    <EditProvider messageId={messageId}>
      <Composer.Frame>
        <Composer.Input />
        <Composer.Footer>
          <Composer.CancelEdit />
          <Composer.SaveEdit />
        </Composer.Footer>
      </Composer.Frame>
    </EditProvider>
  )
}
```

---

## Pattern 4: Lifted State

Components outside the visual hierarchy can access state via provider.

```tsx
function ForwardMessageDialog() {
  return (
    <ForwardMessageProvider>
      <Dialog>
        {/* Composer UI */}
        <Composer.Frame>
          <Composer.Input placeholder="Add a message" />
          <Composer.Footer>
            <Composer.Formatting />
          </Composer.Footer>
        </Composer.Frame>

        {/* Preview OUTSIDE composer but reads its state */}
        <MessagePreview />

        {/* Actions OUTSIDE composer but can submit */}
        <DialogActions>
          <CancelButton />
          <ForwardButton />
        </DialogActions>
      </Dialog>
    </ForwardMessageProvider>
  )
}

// Can access context despite being outside Composer.Frame
function ForwardButton() {
  const { actions: { submit } } = use(ComposerContext)
  return <Button onPress={submit}>Forward</Button>
}

function MessagePreview() {
  const { state } = use(ComposerContext)
  return <Preview message={state.input} attachments={state.attachments} />
}
```

**Key insight:** Provider boundary matters, not visual nesting.

---

## Pattern 5: Children Over Render Props

Use children for composition, render props only when passing data.

```tsx
// BAD: Render props for structure
<Composer
  renderHeader={() => <CustomHeader />}
  renderFooter={() => <Formatting />}
  renderActions={() => <Submit />}
/>

// GOOD: Children for structure
<Composer.Frame>
  <CustomHeader />
  <Composer.Input />
  <Composer.Footer>
    <Formatting />
    <Submit />
  </Composer.Footer>
</Composer.Frame>
```

**When render props ARE appropriate:**

```tsx
// Passing data to children
<List
  data={items}
  renderItem={({ item, index }) => <Item item={item} index={index} />}
/>
```

---

## Pattern 6: Decouple State from UI

Only the provider knows how state is managed. UI consumes the interface.

```tsx
// BAD: UI coupled to state implementation
function ChannelComposer({ channelId }) {
  const state = useGlobalChannelState(channelId)  // Knows about global state
  const { submit } = useChannelSync(channelId)    // Knows about sync
  
  return <Composer.Input value={state.input} onChange={...} />
}

// GOOD: State isolated in provider
function ChannelProvider({ channelId, children }) {
  const { state, update, submit } = useGlobalChannel(channelId)
  
  return (
    <Composer.Provider
      state={state}
      actions={{ update, submit }}
      meta={{ inputRef: useRef(null) }}
    >
      {children}
    </Composer.Provider>
  )
}

// UI only knows the interface
function ChannelComposer() {
  return (
    <Composer.Frame>
      <Composer.Input />  {/* Works with any provider */}
      <Composer.Submit />
    </Composer.Frame>
  )
}
```

---

## Quick Reference

| Anti-Pattern | Solution |
|--------------|----------|
| Boolean props | Explicit variant components |
| Render props for structure | Children composition |
| State in component | Lift to provider |
| Coupled to state impl | Generic context interface |
| Many conditional renders | Compose pieces explicitly |

---

## Files

- `rules/architecture-avoid-boolean-props.md` - Detailed boolean prop guidance
- `rules/architecture-compound-components.md` - Compound component pattern
- `rules/state-context-interface.md` - Context interface design
- `rules/state-decouple-implementation.md` - State isolation
- `rules/state-lift-state.md` - Provider pattern
- `rules/patterns-explicit-variants.md` - Variant components
- `rules/patterns-children-over-render-props.md` - Composition over callbacks

---

## NEVER

- Add boolean props to customize behavior (use composition)
- Create components with more than 2-3 boolean mode props
- Couple UI components to specific state implementations
- Use render props when children would work
- Trap state inside components when siblings need access

Related Skills

testing-patterns

7
from wpank/ai

Unit, integration, and E2E testing patterns with framework-specific guidance. Use when asked to "write tests", "add test coverage", "testing strategy", "test this function", "create test suite", "fix flaky tests", or "improve test quality".

e2e-testing-patterns

7
from wpank/ai

Build reliable, fast E2E test suites with Playwright and Cypress. Critical user journey coverage, flaky test elimination, CI/CD integration.

websocket-hub-patterns

7
from wpank/ai

Horizontally-scalable WebSocket hub pattern with lazy Redis subscriptions, connection registry, and graceful shutdown. Use when building real-time WebSocket servers that scale across multiple instances. Triggers on WebSocket hub, WebSocket scaling, connection registry, Redis WebSocket, real-time gateway, horizontal scaling.

realtime-react-hooks

7
from wpank/ai

React hooks for real-time data with SSE, WebSocket, and SWR integration. Covers connection management, reconnection logic, and optimistic updates. Use when building React apps with real-time features. Triggers on SSE hook, WebSocket hook, real-time React, useEventSource, live updates.

workflow-patterns

7
from wpank/ai

Systematic task implementation using TDD, phase checkpoints, and structured commits. Ensures quality through red-green-refactor cycles, 80% coverage gates, and verification protocols before proceeding.

estimation-patterns

7
from wpank/ai

Practical estimation techniques for software tasks — methods comparison, decomposition, complexity multipliers, buffer calculation, bias awareness, and communication strategies. Use when estimating features, sprint planning, or presenting timelines to stakeholders.

10x-patterns

7
from wpank/ai

Patterns and practices that dramatically accelerate development velocity. Covers parallel execution, automation, feedback loops, workflow optimization, and anti-pattern avoidance. Use when starting projects, planning sprints, optimizing workflows, or onboarding developers.

react-performance

7
from wpank/ai

React and Next.js performance optimization patterns. Use when writing, reviewing, or refactoring React/Next.js code to ensure optimal performance. Triggers on tasks involving components, data fetching, bundle optimization, re-render reduction, or server component architecture.

react-modernization

7
from wpank/ai

No description provided.

react-composition

7
from wpank/ai

React composition patterns for scalable component architecture. Use when refactoring components with boolean prop proliferation, building flexible component libraries, designing reusable component APIs, or working with compound components and context providers.

react-best-practices

7
from wpank/ai

React and Next.js performance optimization guidelines from Vercel Engineering. 57 rules across 8 categories for writing, reviewing, and refactoring React code.

loading-state-patterns

7
from wpank/ai

Patterns for skeleton loaders, shimmer effects, and loading states that match design system aesthetics. Covers skeleton components, shimmer animations, and progressive loading. Use when building polished loading experiences. Triggers on skeleton, loading state, shimmer, placeholder, loading animation.