React Patterns
Composition Over Configuration - Let Consumers Build, Not Configure
March 3, 2026
The more your component does, the more props it needs. showHeader, showFooter, isCompact, variant="thread". Before long you're passing a dozen flags and nobody can tell what the component will actually render. There's a simpler approach: composition over configuration. Give consumers building blocks and let them assemble the UI they need.
The problem: one component, too many knobs
Imagine a message composer used in channels, threads, and edit mode. It's tempting to drive everything with props:
<Composer
isThread
isEditing={false}
channelId="abc"
showAttachments
showFormatting={false}
renderCustomFooter={() => <MentionPicker />}
/>What does this render? You have to trace through conditionals. Adding a new use case means another prop. The API grows and the component becomes a configuration surface instead of a clear, composable UI.
The fix: expose pieces, let consumers compose
Instead of one configurable component, expose small pieces and let the caller arrange them:
// Channel composer - only what a channel needs
function 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"
function 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>
);
}Each screen composes only what it needs. No booleans, no hidden behavior. The code reads like the UI: structure is explicit and easy to change. That's composition over configuration - fewer props, clearer intent, and components that scale.
Related content
Build a Redux Store From Scratch - Learn State Management by Implementing It
Implement a minimal Redux-style store from scratch: getState, dispatch, subscribe, and reducers. Understand how global state works and when to use it in real apps like todos or carts
Read moreCompose Internals - Subcomponents Read From Context, Not Props
Compound components shouldn't receive state and callbacks through props. They read from a shared context so the same UI works with different state sources - local, global, or server.
Read moreExplicit Component Variants - Name the Use Case, Drop the Booleans
One component with isThread, isEditing, isForwarding is hard to reason about. Create named variants - ThreadComposer, EditComposer - so each screen is explicit and self-documenting.
Read more