Deft
Ask AI

Search

Search skills, authors and topics

vercel-labs / agent-skills

vercel-composition-patterns

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.

Install

npx skills add https://github.com/vercel-labs/agent-skills --skill vercel-composition-patterns
title
Create Explicit Component Variants
impact
MEDIUM
impactDescription
self-documenting code, no hidden conditionals
tags
composition, variants, architecture

Create Explicit Component Variants

Instead of one component with many boolean props, create explicit variant components. Each variant composes the pieces it needs. The code documents itself.

Incorrect (one component, many modes):

tsx
// What does this component actually render?<Composer  isThread  isEditing={false}  channelId='abc'  showAttachments  showFormatting={false}/>

Correct (explicit variants):

tsx
// Immediately clear what this renders<ThreadComposer channelId="abc" />
// Or<EditMessageComposer messageId="xyz" />
// Or<ForwardMessageComposer messageId="123" />

Each implementation is unique, explicit and self-contained. Yet they can each use shared parts.

Implementation:

tsx
function ThreadComposer({ channelId }: { channelId: string }) {  return (    <ThreadProvider channelId={channelId}>      <Composer.Frame>        <Composer.Input />        <AlsoSendToChannelField channelId={channelId} />        <Composer.Footer>          <Composer.Formatting />          <Composer.Emojis />          <Composer.Submit />        </Composer.Footer>      </Composer.Frame>    </ThreadProvider>  )}
function EditMessageComposer({ messageId }: { messageId: string }) {  return (    <EditMessageProvider messageId={messageId}>      <Composer.Frame>        <Composer.Input />        <Composer.Footer>          <Composer.Formatting />          <Composer.Emojis />          <Composer.CancelEdit />          <Composer.SaveEdit />        </Composer.Footer>      </Composer.Frame>    </EditMessageProvider>  )}
function ForwardMessageComposer({ messageId }: { messageId: string }) {  return (    <ForwardMessageProvider messageId={messageId}>      <Composer.Frame>        <Composer.Input placeholder="Add a message, if you'd like." />        <Composer.Footer>          <Composer.Formatting />          <Composer.Emojis />          <Composer.Mentions />        </Composer.Footer>      </Composer.Frame>    </ForwardMessageProvider>  )}

Each variant is explicit about:

  • What provider/state it uses
  • What UI elements it includes
  • What actions are available

No boolean prop combinations to reason about. No impossible states.