Skip to content
AI & Agents
Skill

/applying-composition-patterns

React composition patterns that scale. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or during architecture review.

From plugin
ring
20577 skills42 agents1 command
Install
$ npx -y skills add LerianStudio/ring --skill applying-composition-patterns --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/applying-composition-patterns

Context preview

The summary Claude sees to decide when to auto-load this skill.

React composition patterns that scale. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or during architecture review.

SKILL.md

applying-composition-patterns.SKILL.md
name: ring:applying-composition-patterns
description: "React composition patterns that scale. Avoid boolean prop proliferation by using compound components, lifting state, and composing internals. Use when refactoring components with boolean prop proliferation, building flexible component libraries, or during architecture review. Skip for simple components with 1-2 props or non-React code."
paths: ["**/*.tsx", "**/*.jsx"]

Applying Composition Patterns

When to use

  • Refactoring components with boolean prop proliferation
  • Building flexible, reusable component libraries
  • Architecture review of React component hierarchies
  • Component has grown to 3+ boolean props controlling behavior
  • Multiple render props or conditional rendering branches

Skip when

  • Simple components with 1-2 props and no conditional rendering
  • Non-React code
  • Prototype or throwaway code where flexibility doesn't matter
  • Component is leaf-level with no composition concerns

Related

**Complementary:** ring:checking-frontend-quality — validate component quality after refactoring

---

Abstract

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.

---

Table of Contents

1. [Component Architecture](#1-component-architecture) — **HIGH**

  • 1.1 [Avoid Boolean Prop Proliferation](#11-avoid-boolean-prop-proliferation)
  • 1.2 [Use Compound Components](#12-use-compound-components)

2. [State Management](#2-state-management) — **MEDIUM**

  • 2.1 [Decouple State Management from UI](#21-decouple-state-management-from-ui)
  • 2.2 [Define Generic Context Interfaces for Dependency Injection](#22-define-generic-context-interfaces-for-dependency-injection)
  • 2.3 [Lift State into Provider Components](#23-lift-state-into-provider-components)

3. [Implementation Patterns](#3-implementation-patterns) — **MEDIUM**

  • 3.1 [Create Explicit Component Variants](#31-create-explicit-component-variants)
  • 3.2 [Prefer Composing Children Over Render Props](#32-prefer-composing-children-over-render-props)

4. [React 19 APIs](#4-react-19-apis) — **MEDIUM**

  • 4.1 [React 19 API Changes](#41-react-19-api-changes)

---

1. Component Architecture

**Impact: HIGH**

Fundamental patterns for structuring components to avoid prop proliferation and enable flexible composition.

1.1 Avoid Boolean Prop Proliferation

**Impact: CRITICAL (prevents unmaintainable component variants)**

Don't add boolean props like `isThread`, `isEditing`, `isDMThread` to customize component behavior. Each boolean doubles possible states and creates unmaintainable conditional logic. Use composition instead.

**Incorrect: boolean props create exponential complexity**

const Composer = ({
  onSubmit,
  isThread,
  channelId,
  isDMThread,
  dmId,
  isEditing,
  isForwarding
}: Props) => {
  return (
    <form>
      <Header />
      <Input />
      {isDMThread ? (
        <AlsoSendToDMField id={dmId} />
      ) : isThread ? (
        <AlsoSendToChannelField id={channelId} />
      ) : null}
      {isEditing ? (
        <EditActions />
      ) : isForwarding ? (
        <ForwardActions />
      ) : (
        <DefaultActions />
      )}
      <Footer onSubmit={onSubmit} />
    </form>
  )
}

**Correct: composition eliminates conditionals**

// Channel composer
const ChannelComposer = () => {
  return (
    <Composer.Frame>
      <Composer.Header />
      <Composer.Input />
      <Composer.Footer>
        <Composer.Attachments />
        <Composer.Formatting />
        <Composer.Emojis />
        <Composer.Submit />
      </Composer.Footer>
    </Composer.Frame>
  )
}

// Thread composer - adds "also send to channel" field
const ThreadComposer = ({ channelId }: { channelId: string }) => {
  return (
    <Composer.Frame>
      <Composer.Header />
      <Composer.Input />
      <AlsoSendToChannelField id={channelId} />
      <Composer.Footer>
        <Composer.Formatting />
        <Composer.Emojis />
        <Composer.Submit />
      </Composer.Footer>
    </Composer.Frame>
  )
}

// Edit composer - different footer actions
const EditComposer = () => {
  return (
    <Composer.Frame>
      <Composer.Input />
      <Composer.Footer>
        <Composer.Formatting />
        <Composer.Emojis />
        <Composer.CancelEdit />
        <Composer.SaveEdit />
      </Composer.Footer>
    </Composer.Frame>
  )
}

Each variant is explicit about what it renders. We can share internals without sharing a single monolithic parent.

1.2 Use Compound Components

**Impact: HIGH (enables flexible composition without prop drilling)**

Structure complex components as compound components with a shared context. Each subcomponent accesses shared state via context, not props. Consumers compose the pieces they need.

**Incorrect: monolithic component with render props**

const Composer = ({
  renderHeader,
  renderFooter,
  renderActions,
  showAttachments,
  showFormatting,
  showEmojis
}: Props) => {
  return (
    <form>
      {renderHeader?.()}
      <Input />
      {showAttachments && <Attachments />}
      {renderFooter ? (
        renderFooter()
      ) : (
        <Footer>
          {showFormatting && <Formatting />}
          {showEmojis && <Emojis />}
          {renderActions?.()}
        </Footer>
      )}
    </form>
  )
}

**Correct: compound components with shared context**

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

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

const ComposerFrame = ({ children }: { children: React.ReactNode }) => {
  return <form>{children}</form>
}

const ComposerInput = () => {
  const
Read more
Ships withring

Proven engineering practices, enforced through skills. Ring is a comprehensive skills library and workflow system for AI agents that transforms how AI assistants approach software development.

Get the whole plugin

Other skills on ring.