CodePark/ questions / Component patterns
START PRACTICINGPRACTICE
Frontend question · React › Component patterns

What are compound components, and how would you implement them?

const TabsContext = createContext(null);

function Tabs({ defaultId, children }) {
  const [activeId, setActiveId] = useState(defaultId);
  return <TabsContext value={{ activeId, setActiveId }}>{children}</TabsContext>;
}

function Tab({ id, children }) {
  const { activeId, setActiveId } = useContext(TabsContext);
  return <button aria-selected={activeId === id} onClick={() => setActiveId(id)}>{children}</button>;
}

Compound components are a set of components that work together and share hidden state. An example is <Tabs>, <Tabs.List>, <Tabs.Tab> and <Tabs.Panel>. The user arranges them freely in JSX, while the parent manages the shared state. Think of <select> and <option> in HTML: they only make sense together.

The modern implementation uses context:

  • The parent Tabs holds activeId in state.
  • It provides { activeId, setActiveId } through a context.
  • Each Tab reads the context to know if it is selected, and to change the selection.
  • Each Panel renders only when its id matches.

Also expose a custom hook that throws a clear error when a piece is used outside the parent.

This gives a flexible, readable API without long lists of configuration props. Users can place and style the pieces as they like. Many headless UI libraries are built this way. Headless means they provide behaviour but no styles.

  • Compound components are related components that share hidden state.
  • The parent owns the state and provides it through context.
  • The children read the context to render and to update the state.
  • A guard hook throws a clear error when a piece is used outside the parent.
  • Users get flexible markup instead of many configuration props.