React has no class hierarchy you extend. You build complex UIs by nesting components inside components and passing pieces of UI as props or children. That's composition. It scales further than any class tree.
Two composition idioms
Almost all React composition reduces to two patterns:
The children prop — the parent renders a frame and lets children fill the inside.
Slot props — named props (other than children) that take React nodes, letting a parent compose into specific positions.
You'll see slot-prop layouts (header / body / footer) in dashboards, dialogs, and cards. The children prop alone covers the simple case; slot props win when there are multiple distinct positions.
The compound component pattern
Sometimes you want callers to write <Tabs><Tab>A</Tab><Tab>B</Tab></Tabs>. The Tabs parent owns the active state, and Tab children read it from context. This is compound components — parent and children share an implicit state contract. Use sparingly; great for libraries, can be over-engineered for app code.
The asChild / Slot pattern
A pattern Radix UI popularized: instead of cloning a styled <button> into a <Link>, you let callers pass asChild and the component renders its children as the actual element, merging in its own behavior. Lets the same Button become a real anchor when wrapped around a <Link>.
If you reach for a higher-order component, stop. Composition is almost always cleaner. The cases where HOCs win are vanishingly rare in 2026 — usually data-fetching wrappers from libraries (which themselves use hooks now). Lesson 6 of this track is the death notice.
Code
children — the simple case·tsx
function Card({ children }: { children: React.ReactNode }) {
return (
<article className="rounded-card bg-bg-elevated p-6 shadow-sm">
{children}
</article>
);
}
// Caller fills the inside:
<Card>
<h2>Hello</h2>
<p>This is a card.</p>
</Card>
Build a Modal component with three slot props: header, body, footer. Then build a sibling Modal2 that uses the compound-component pattern with Modal2.Header, Modal2.Body, Modal2.Footer children. Use both to render the same delete-confirmation UI. Notice which one feels more natural to read at the call site, and which one is easier to define.
Hint
For the compound pattern: Modal2.Header = function Header(...) after defining Modal2. The children inspect their position via context or a marker prop.
Progress
Progress is local-only — sign in to sync across devices.