Compound components share implicit state through context, providing a flexible API.
Code:
1import { createContext, useContext, useState } from "react";23// 1. Create context4const AccordionContext = createContext<{5 openIndex: number;6 setOpenIndex: (index: number) => void;7} | null>(null);89// 2. Parent component manages state10function Accordion({ children, defaultIndex = 0 }) {11 const [openIndex, setOpenIndex] = useState(defaultIndex);1213 return (14 <AccordionContext.Provider value={{ openIndex, setOpenIndex }}>15 <div className="accordion">{children}</div>16 </AccordionContext.Provider>17 );18}1920// 3. Child components consume context21function AccordionItem({ index, children }) {22 const { openIndex, setOpenIndex } = useContext(AccordionContext)!;23 const isOpen = openIndex === index;2425 return (26 <div className={`item ${isOpen ? "open" : ""}`}>27 {children}28 </div>29 );30}3132function AccordionHeader({ index, children }) {33 const { setOpenIndex } = useContext(AccordionContext)!;3435 return (36 <button onClick={() => setOpenIndex(index)}>37 {children}38 </button>39 );40}4142function AccordionPanel({ children }) {43 return <div className="panel">{children}</div>;44}4546// 4. Usage — flexible composition47<Accordion>48 <AccordionItem index={0}>49 <AccordionHeader index={0}>Section 1</AccordionHeader>50 <AccordionPanel>Content 1</AccordionPanel>51 </AccordionItem>52 <AccordionItem index={1}>53 <AccordionHeader index={1}>Section 2</AccordionHeader>54 <AccordionPanel>Content 2</AccordionPanel>55 </AccordionItem>56</Accordion>
Benefits:
Examples: Tabs, Accordion, Menu, Dialog