Compose the parts you need

Split a big component into parts that read one shared context.

React docsreact.dev
Context lets the parent component make some information available to any component in the tree below it—no matter how deep—without passing it explicitly through props.
Passing Data Deeply with ContextRead docs ↗

From vercel-composition-patterns, rule compound-components.

Rearrange the composer

Press Shuffle, or drag a part by its handle.

Monolith + show flagsBad
    order fixed inside Composer
    showAttachments, showFormatting, …
    Compound partsGood
      order lives at the call site
      <Composer.Frame>{parts}</Composer.Frame>
      const ComposerContext = createContext<ComposerContextValue | null>(null)
      
      function ComposerProvider({ children, state, actions, meta }: ProviderProps) {
        return (
          <ComposerContext value={{ state, actions, meta }}>
            {children}
          </ComposerContext>
        )
      }
      
      function ComposerInput() {
        const {
          state,
          actions: { update },
          meta: { inputRef },
        } = use(ComposerContext)
        return (
          <TextInput
            ref={inputRef}
            value={state.input}
            onChangeText={(text) => update((s) => ({ ...s, input: text }))}
          />
        )
      }
      
      // Export as compound component
      const Composer = {
        Provider: ComposerProvider,
        Frame: ComposerFrame,
        Input: ComposerInput,
        Submit: ComposerSubmit,
        Header: ComposerHeader,
        Footer: ComposerFooter,
        Attachments: ComposerAttachments,
        Formatting: ComposerFormatting,
        Emojis: ComposerEmojis,
      }

      Your own part joins in

      Add a part the library never shipped, then type.

      MonolithBad
      AttachAaSend
      no slot for it
      <Composer />
      Compound + contextGood
      AttachAaSend
      not added yet
      use(ComposerContext).state.input
      // Your own part, written outside the library
      function CharCount() {
        const { state } = use(ComposerContext)
        return <span>{state.input.length} / 280</span>
      }
      
      <Composer.Provider state={state} actions={actions} meta={meta}>
        <Composer.Frame>
          <Composer.Input />
          <Composer.Footer>
            <Composer.Formatting />
            <CharCount />
            <Composer.Submit />
          </Composer.Footer>
        </Composer.Frame>
      </Composer.Provider>

      Why it matters, pros and cons

      Why it matters

      Each part reads shared state from context, so callers pick and order parts without new props.

      Pros

      • Order and inclusion live at the call site.
      • Your own parts get the same state and actions.
      • No prop drilling into nested parts.

      Cons

      • More exports to learn than one component.
      • Parts throw outside the provider; guard the read.
      • Overkill for a leaf like a badge.