Compound components allow related components to share state and behavior in a flexible, decoupled way. These components work together like a team, allowing for a more declarative API, perfect for building reusable libraries like dropdowns, tabs, or modals.
Step 1: Creating the Parent Component
Let's build a simple Accordion using compound components. The parent component will manage the state and share it with the children.
import React, { useState, createContext, useContext } from 'react';
const AccordionContext = createContext();
const Accordion = ({ children }) => {
const [openIndex, setOpenIndex] = useState(null);
const toggleIndex = (index) => {
setOpenIndex(index === openIndex ? null : index);
};
return (
<AccordionContext.Provider value={{ openIndex, toggleIndex }}>
<div className="accordion">{children}</div>
</AccordionContext.Provider>
);
};
Step 2: Creating Child Components
The AccordionItem, AccordionHeader, and AccordionBody components will consume the context to know when to expand or collapse.
const AccordionItem = ({ index, children }) => {
const { openIndex } = useContext(AccordionContext);
return <div>{openIndex === index && children}</div>;
};
const AccordionHeader = ({ index, children }) => {
const { toggleIndex } = useContext(AccordionContext);
return <h2 onClick={() => toggleIndex(index)}>{children}</h2>;
};
const AccordionBody = ({ children }) => {
return <div>{children}</div>;
};
Step 3: Using the Compound Components
Now, use the compound components with a clean and intuitive API.
const App = () => {
return (
<Accordion>
<AccordionHeader index={0}>Section 1</AccordionHeader>
<AccordionItem index={0}>
<AccordionBody>Content for section 1</AccordionBody>
</AccordionItem>
<AccordionHeader index={1}>Section 2</AccordionHeader>
<AccordionItem index={1}>
<AccordionBody>Content for section 2</AccordionBody>
</AccordionItem>
</Accordion>
);
};
Why Use Compound Components?
- Decoupled structure: Parent and child components are more flexible and easier to manage.
- Flexible API: Consumers can easily compose and arrange the UI without coupling logic.