Why Composition Beats Configuration
Maintainer at Rad UI
A deep dive into why prop-heavy React APIs age poorly — and how composition gives developers both constraint and creative freedom.
Why Composition Beats Configuration
The longer you work with React, the more you start noticing a pattern.
Every library starts clean — a handful of props, a simple example in the README, and a promise of flexibility.
Then it grows.
Suddenly you’re staring at a <Button> with 47 props.
variant, size, icon, iconPosition, tone, intent, shape, loading, disabled, align, asChild, asLink, withTooltip, tooltipDelay, tooltipSide, tooltipOffset… you get the picture.
Prop-heavy APIs feel great at first — “look at all the things I can configure!” — but they age like milk. Let’s explore why that happens, and why composition is the better long-term philosophy.
Configuration: The Illusion of Control
A prop-based API is seductive. It tells you, “Don’t worry, we’ve already thought of everything. Just pick your flavor.”
But every prop is a promise.
A guarantee the component must honor — in perpetuity. Each one expands the surface area for bugs, regressions, and design debt. And every new use case forces a fork in the code path: if variant === "ghost" and tone === "danger" but asChild is true, then do something else entirely.
The API starts to look like a buffet where every dish tastes slightly of compromise.
You end up with a component that’s easy to use once but impossible to extend later. You can’t express “Button, but with a badge and a split dropdown,” without begging the maintainer to add hasBadge and splitMenu props.
And that’s how configuration breeds bloat.
Composition: The Art of Assembly
React’s best idea wasn’t JSX or hooks. It was composition — the notion that you can build complexity by combining small, single-purpose parts.
Instead of passing a hundred knobs into one god-component, you compose smaller primitives that do one thing well.
Compare the two approaches:
Configuration-style:
<Button
variant="outline"
icon="download"
tooltip="Save as PDF"
onClick={handleSave}
/>
`
Composition-style:
<Tooltip content="Save as PDF">
<Button variant="outline" onClick={handleSave}>
<DownloadIcon />
</Button>
</Tooltip>
Same behavior, but radically different power dynamics.
In the first, the Button is in charge. You’re limited to what its API designer imagined. In the second, you are in charge. You can wrap, nest, or replace components as needed.
Composition turns your UI layer into LEGO blocks, not an IKEA manual.
Constraints as a Creative Tool
The misconception is that composition removes constraints. In truth, it gives you the right kind of constraints.
Configuration says, “Here’s every option you might need.” Composition says, “Here’s a small set of predictable pieces — now make something great.”
Developers love to talk about “flexibility,” but flexibility without structure is chaos. Composition gives structure through clear boundaries. Each primitive enforces its own semantics — Tooltip handles positioning, Button handles click interactions, Icon handles sizing. Their responsibilities are explicit and interchangeable.
When a team adopts this mindset, design systems stop being static themes and start being languages. You’re not asking, “Does our button support this case?” but “Can we say this sentence with our vocabulary?”
Why Prop-Heavy APIs Age Poorly
Because they fossilize assumptions. They encode yesterday’s design language into tomorrow’s constraints.
When your designer inevitably rebrands the app and buttons gain gradients or new spacing rules, you’ll find those assumptions buried deep in prop logic that can’t adapt without breaking things.
Composition decouples those assumptions. You can redesign the Button component without touching Tooltip or Icon, and still express the same sentence differently.
That’s how systems like Rad UI or Radix stay relevant through multiple design eras — their primitives are small, composable, and opinion-light.
Constraint and Creativity, Hand in Hand
The most powerful UIs come from systems that encourage invention without inviting chaos. Composition is that middle path — a philosophy that honors both discipline and expression.
Every prop you add to a component is a debt. Every composable primitive you design is an investment.
So next time you’re tempted to add hasTooltip or withDropdown to your Button, stop. Ask instead:
“What if I composed it?”
That single question is the gateway from configuration hell to creative freedom.
Composition isn’t just a coding pattern. It’s a worldview. It trusts developers to build. It trusts teams to evolve. And it trusts the interface — the language of components — to express ideas yet unimagined.