Suggest an editImprove this articleRefine the answer for “What does the "compound components" pattern do with context?”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Compound Components (composite components)** are a pattern where several related components work together as a single "component group", communicating through React Context instead of manually passed props. **Key point:** the parent component manages the state and provides it through context, while the child components simply subscribe to that context, so prop drilling disappears entirely.Shown above the full answer for quick recall.Answer (EN)Image## What "Compound Components" are **Compound Components (composite components)** are a pattern where **several related components** work **together** as a single "component group". Usually we have a "parent" and "child elements" that **communicate with each other through React Context** instead of passing props manually. --- ## Example (intuitively) ### Without the pattern ```javascript <Tabs> <TabList> <Tab label="Description" activeTab={activeTab} setActiveTab={setActiveTab} /> <Tab label="Reviews" activeTab={activeTab} setActiveTab={setActiveTab} /> </TabList> <TabPanels activeTab={activeTab}> <TabPanel index={0}>Content 1</TabPanel> <TabPanel index={1}>Content 2</TabPanel> </TabPanels> </Tabs> ``` Downsides: - you have to thread a bunch of props (`activeTab`, `setActiveTab`); - the components are "tightly coupled" - using them separately is inconvenient. --- ## With the Compound Components pattern ### Goal: - For `Tabs`, `TabList`, `Tab`, `TabPanel` **to know their own state on their own** through an **internal context**; - for the code to look natural: ```javascript <Tabs> <Tabs.List> <Tabs.Tab>Description</Tabs.Tab> <Tabs.Tab>Reviews</Tabs.Tab> </Tabs.List> <Tabs.Panels> <Tabs.Panel>Content 1</Tabs.Panel> <Tabs.Panel>Content 2</Tabs.Panel> </Tabs.Panels> </Tabs> ``` --- ## How it works ### 1. Create the context ```javascript const TabsContext = createContext(null); ``` ### 2. The parent component (Provider) ```javascript function Tabs({ children }) { const [activeIndex, setActiveIndex] = useState(0); const value = useMemo(() => ({ activeIndex, setActiveIndex }), [activeIndex]); return ( <TabsContext.Provider value={value}> <div className="tabs">{children}</div> </TabsContext.Provider> ); } ``` ### 3. Child components - context subscribers ```javascript function TabList({ children }) { return <div className="tab-list">{children}</div>; } function Tab({ children, index }) { const { activeIndex, setActiveIndex } = useContext(TabsContext); const isActive = index === activeIndex; return ( <button className={isActive ? "active" : ""} onClick={() => setActiveIndex(index)} > {children} </button> ); } function Panels({ children }) { return <div className="tab-panels">{children}</div>; } function Panel({ children, index }) { const { activeIndex } = useContext(TabsContext); return activeIndex === index ? <div>{children}</div> : null; } ``` ### 4. Assembling the "compound" component ```javascript Tabs.List = TabList; Tabs.Tab = Tab; Tabs.Panels = Panels; Tabs.Panel = Panel; ``` --- ## What context does here Context is used as an **internal linking mechanism** between components, so they can **"know" the parent's (Tabs) state** **without requiring props** at every level. That is: - `Tabs` manages the state (the active tab); - `Tabs.Tab` and `Tabs.Panel` are simply "subscribed" to that context; - everything synchronizes automatically. --- ## Advantages of the pattern | Advantage | Description | |---|---| | Clean API | Nested JSX reflects the logic's hierarchy | | Reusability | Components can be reused independently | | Encapsulation | The Tabs state is hidden, accessible only through context | | Flexibility | You can insert your own components between them | | No prop drilling | No props are passed down manually | --- ## Where this is used This pattern is used everywhere: - in **Headless UI**, **Radix UI**, **shadcn/ui**, **React Aria**; - for **Tabs**, **Accordion**, **Dropdown**, **Menu**, **Modal**, **Form**, **Stepper**. --- ## Summary **Compound Components + Context =** > a flexible interface where child components automatically know > which context they are in, and synchronize without props. --- ## The pattern's formula: 1. Create a context inside the "parent"; 2. Provide the value through `<Provider>`; 3. Child components pull the state from the context; 4. Export the child components as properties of the main one.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.