Composition Over Inheritance: Slots, Projection, Render Props A component needs to support one more variant. The easy move is to add a prop: , then , then . Six months later the component has twenty props, half of them booleans that only make sense in combination with three others, and nobody remembers which combinations are actually supported. That's inheritance-style thinking wearing a component's clothes: one base implementation, extended by configuration, trying to anticipate every future case up front. The alternative is composition — instead of teaching one component every possible variant, give the caller a point where they can supply their own behavior, and let variants exist outside the component entirely. Why configuration doesn't scale Every new prop is a new branch inside the component, and every combination of props is a code path someone has to reason about — whether or not that combination is ever actually used. A component with a slot instead of an prop doesn't need to know about your new variant at all. It just needs to call whatever you handed it. The component stops growing every time a new use case appears. That's the whole win: composition moves variation to the edges, where it belongs, instead of accumulating in the center, where it doesn't. The tell that you need this is the same tell from prop-explosion in general: when you're adding a flag to handle one specific caller's need, and that flag will be irrelevant — or actively confusing — to every other caller. Giving the caller a point to inject behavior, not just markup A previous lesson covered slots for static content — a header, a body. This is the same idea one level up: instead of projecting fixed markup, you project a function or template that the component invokes per item , so the caller controls exactly how each piece renders without the component needing a branch for it. In Angular Use a structural directive with , so the caller supplies a template and the component just renders it once per item: In React The equivalent is a render prop — the caller passes a function instead of static children, and the component calls it per item: Neither component needs to know what a is, or that one exists. Add a new caller with entirely different rendering needs, and the component doesn't change at all. The framework changes the syntax, not the decision. The Trade-off: Is a Render Slot Worth More Than a Prop? A render slot is more ceremony up front than a boolean flag — a template reference or a function prop, instead of . Whether that ceremony pays for itself depends entirely on how many variants actually show up. The pain, concretely A configuration-driven degrades exactly like the Tabs example from later in this chapter — one flag at a time: v1: — one variant, a simple internal , ships in an afternoon. v2: Design wants a compact row layout for the mobile view. — the internal becomes a . v3: A third screen wants the compact layout, but with a badge in some cases. — now the variant name itself is describing a combination of two independent concerns mashed into one string. v4: A fourth screen needs a hover preview. There's no clean variant name left that doesn't read like a sentence, and every new visual idea requires editing 's source — even though 's own job (iterating and keying items) hasn't changed at all. The component was never wrong about how to loop over an array. It became wrong the moment it also tried to own every possible way to render one row of it. Side-by-side Variant-prop switch Render-slot composition --- --- --- Adding a new visual variant Edit 's source, extend the Caller writes a new /template — untouched Combining two visual ideas (compact + badge) New variant string that encodes both, e.g. Caller's own render function composes freely — no naming gymnastics Who owns rendering knowledge must know about every visual style that will ever exist only knows how to iterate; rendering knowledge lives with the caller Upfront cost None — a string prop is the simplest thing to write A template reference or function prop — slightly more setup The signal to switch The moment you're tempted to add a second variant-selecting prop — or extend an existing variant name to cover a new combination — that's the trigger. A single fixed rendering need doesn't justify a slot; a second one does. Start simple If a component genuinely renders exactly one kind of item and no other is realistically coming, a plain prop (or even hardcoded markup) is the right amount of engineering — building a render slot for a variant that doesn't exist yet is solving a problem you don't have. Reach for composition the moment the second real variant shows up. The rule When a component needs to support cases it can't predict, give the caller a composition point — a template or render function — instead of adding another configuration flag. Configuration makes the component grow forever. Composition lets variation live at the edges, where new cases don't require t…