tezvyn:

Compound Components: Build Flexible APIs via Shared State

AI-drafted, machine-checkedSource: epicreact.devintermediate

Think of HTML's `<select>` and `<option>`. The Compound Component pattern lets a parent manage state while children act as declarative configuration. It's used for flexible UI like tabs or accordions.

WHY IT EXISTS: To avoid "prop explosion." As a component grows more complex, managing every variation through props becomes unwieldy and inflexible. The Compound Component pattern provides a clean, declarative API for complex UI by breaking a single monolithic component into a family of cooperating components.

THE MENTAL MODEL: Think of native HTML's <select> and <option> tags. The parent <select> manages the state—which option is selected, its value—while the child <option> tags simply declare the available choices. They work together seamlessly without you having to manually wire state between them. This pattern brings that same declarative power to your own React components.

HOW IT WORKS: The parent component creates and manages the shared logic and state. It then uses React's Context API to pass that state and any helper functions down to its descendants. The child components consume this context to read the state or call functions to update it. This creates an implicit link, allowing the components to coordinate their behavior even though the developer using them just nests them in JSX.

WHEN TO USE IT: Reach for this pattern when building UI that needs to be highly flexible and composable, like custom tabs, accordions, or menus. It's perfect for component libraries where you want to give users maximum control over structure and rendering while abstracting away the state management. It keeps your component API clean and avoids a long list of configuration props.

WHEN NOT TO USE IT: This pattern is overkill for simple components that don't require much composition. If a component's variations can be handled with a few simple props, stick with that. Also, avoid this pattern if the child components need to function independently, as they are inherently coupled to their parent via context.

ONE CANONICAL EXAMPLE: A custom <Tabs> system. A top-level <Tabs> component manages the activeTab state. It renders a <TabList> for the buttons and a <TabPanels> for the content. Inside, <Tab> and <TabPanel> components use the shared context to know whether they are active and how to change the active state. The user simply writes <Tabs><TabList><Tab>...</Tab></TabList><TabPanels><TabPanel>...</TabPanel></TabPanels></Tabs> and it just works.

Read the original → epicreact.dev

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.