Your Button Has 1,600 Variants and Nobody Can Tell You Why

Someone on a design systems team documented a single button component that had grown to over 1,600 variants. Not 1,600 hypothetical combinations sitting unused in a spreadsheet — 1,600 that had actually been created, named, and shipped somewhere into a Figma file. Nobody could tell you which twelve were load-bearing. That's not an edge case. That's the default failure mode of every design system that survives past its second year, and almost nobody talks about it because "we have too many buttons" doesn't sound like a crisis until you're the engineer who has to implement all of them.
The math nobody runs at the start
A design system starts small and defensible. A Button component gets a primary style, a secondary style, and a size prop — small, medium, large. Six variants. Fine. Then someone needs a destructive action, so there's a danger style. Someone needs a loading state. Someone needs an icon-left and icon-right position. Someone needs a disabled state that's visually distinct from a loading state. Nobody sat down and asked for 200 variants — every single addition was reasonable in isolation. The variant count is the product of every prop's option count, not the sum, and multiplication is what turns six reasonable decisions into a number nobody would have approved if they'd seen it coming.
This is exactly the failure Figma's own product team was responding to when they shipped Component Properties in 2022 — a feature built specifically to let teams collapse combinatorial variant matrices into props that could be toggled independently, instead of hand-building every permutation as a separate named component. That a platform-level feature exists to solve this tells you it wasn't one team's discipline problem. It's what happens by default when component APIs grow without anyone tracking the multiplication.
Design systems researcher Brad Frost has been documenting the downstream version of this for years: in Storybook's own analysis of why most design systems implode, the pattern isn't dramatic failure — it's slow decay. Documentation goes stale first, because updating docs for 200 variants is nobody's job description. Then the variant inventory quietly drifts from what's documented to what's actually used, and the gap between those two lists becomes the real design debt nobody's tracking.
Nobody's measuring the gap, so nobody sees the rot
Here's the part that makes this worse than ordinary technical debt: variant explosion is invisible in the tool where it happens. Figma renders each variant as a clean, correctly-labeled tile in a component set. It looks organized. A hundred and twenty variants sitting in a well-named grid feels like rigor, not risk — the visual order masks the fact that ninety of those tiles have never once shipped in a real product surface.
Nathan Curtis, who's spent more time than almost anyone publicly writing about design system operations, proposed treating this as a data problem rather than a hygiene problem: crawl the actual specs and instances in use, and build a real "analysis of variants" — a measured inventory of what's live versus what's merely documented — instead of trusting the component library's own table of contents to reflect reality. That distinction matters because it changes who's responsible for the fix. If variant explosion is a documentation problem, the fix is "write better docs," which nobody has time for and which decays again within a quarter. If it's a measurement problem, the fix is instrumentation: track which variant props actually get set in production code, and you have an evidence-based deletion list instead of a political argument about which button style someone's attached to.
Brad Frost's own client work backs this up with a number worth sitting with: one engagement had accumulated over 5,000 design tokens across a system's components and variants before anyone audited what was actually load-bearing. That's not a governance failure at the level of "we needed better naming conventions." That's a system that grew without anyone owning the multiplication table.
Composition beats configuration, but only if you enforce it
The fix design systems people reach for first is more governance — a council, a review gate, a rule that new variants need sign-off. This helps at the margins and does almost nothing about the compounding math, because governance slows down additions while doing nothing about the existing combinatorial surface already shipped. You can gate the front door and still be maintaining 1,600 variants from before the gate existed.
The fix that actually addresses the multiplication is architectural: favor composition over configuration. Instead of a Button component with a danger prop and an outline prop and a loading prop that multiply against each other, you build a smaller set of composable primitives — a base Button, a separate IconSlot, a separate LoadingWrapper — and let consuming teams combine them in code rather than requesting a new named variant every time they need a combination the design system didn't anticipate. One documented case in the DEV Community's design systems writing showed a team cutting their component count by roughly 40% and their bundle size by over 20% simply by moving prop-heavy variants into composed patterns instead of pre-built permutations. The variants didn't disappear because the use cases disappeared — they disappeared because the system stopped needing to pre-bake every combination someone might theoretically want.
This is the same underlying failure mode as design tokens that are theoretically sound and practically unmanageable: a system built on the assumption that more granular control is always better, without anyone accounting for what granular control costs at scale. Tokens and variants both fail the same way — beautifully organized in the tool, quietly ungovernable in production, and nobody notices until an engineer asks which of the 40 button styles they're supposed to use for a state the Figma file never named.
What to actually do this quarter
You don't fix an existing 1,600-variant button by holding a meeting about it. You fix it by instrumenting usage — even a rough grep across your codebase for which variant props actually get invoked tells you more than a design review ever will — and then you delete aggressively based on what that data says, not based on who built which variant or how attached anyone is to it. The uncomfortable truth is that most variants exist because removing them feels riskier than leaving them, and that asymmetry is exactly how you end up maintaining hundreds of components nobody's used since the sprint they were built for.
A design system isn't measured by how much a component can do. It's measured by how confidently an engineer can pick the right variant without asking anyone. Every variant past that threshold isn't flexibility — it's a decision the system failed to make on someone else's behalf, over and over, at scale.