Skip to content

Latest commit

 

History

History
142 lines (100 loc) · 3.48 KB

File metadata and controls

142 lines (100 loc) · 3.48 KB

Compound Components

Definition

Compound Components is a design pattern in React where multiple components work together as a group, allowing the parent component to share implicit state with its children via React’s context or props.

The idea: The parent manages the state/behavior, and the children are flexible building blocks that know how to interact with the parent.


Why It Exists

Sometimes, you want to give users more control over a component’s internal layout while still managing a shared state. Instead of passing a huge list of props down to one monolithic component, you split it into smaller related components.

Benefits:

  • Flexible layout control for developers using your component
  • Cleaner API — no long prop lists
  • Children stay in sync through shared context

Classic Example: <Tabs> Component

import React, { createContext, useContext, useState } from 'react';

const TabsContext = createContext();

function Tabs({ children, defaultIndex = 0 }) {
  const [activeIndex, setActiveIndex] = useState(defaultIndex);

  return (
    <TabsContext.Provider value={{ activeIndex, setActiveIndex }}>
      <div className="tabs">{children}</div>
    </TabsContext.Provider>
  );
}

function TabList({ children }) {
  return <div className="tab-list">{children}</div>;
}

function Tab({ index, children }) {
  const { activeIndex, setActiveIndex } = useContext(TabsContext);
  const isActive = activeIndex === index;

  return (
    <button
      style={{
        fontWeight: isActive ? 'bold' : 'normal',
        borderBottom: isActive ? '2px solid blue' : 'none',
      }}
      onClick={() => setActiveIndex(index)}
    >
      {children}
    </button>
  );
}

function TabPanels({ children }) {
  return <div className="tab-panels">{children}</div>;
}

function TabPanel({ index, children }) {
  const { activeIndex } = useContext(TabsContext);
  return activeIndex === index ? <div>{children}</div> : null;
}

// Assign as static properties (optional API style)
Tabs.List = TabList;
Tabs.Tab = Tab;
Tabs.Panels = TabPanels;
Tabs.Panel = TabPanel;

export default Tabs;

Usage:

<Tabs defaultIndex={0}>
  <Tabs.List>
    <Tabs.Tab index={0}>Home</Tabs.Tab>
    <Tabs.Tab index={1}>Profile</Tabs.Tab>
  </Tabs.List>
  <Tabs.Panels>
    <Tabs.Panel index={0}>Home Content</Tabs.Panel>
    <Tabs.Panel index={1}>Profile Content</Tabs.Panel>
  </Tabs.Panels>
</Tabs>

Key Characteristics

  • Parent manages state
  • Children communicate via context
  • Children don’t need prop drilling — they “just work” when placed inside the parent

Pros & Cons

Pros

  • Very flexible API for component consumers
  • Avoids prop drilling
  • Keeps components modular & reusable

⚠️ Cons

  • Slightly more boilerplate to set up
  • Requires context knowledge
  • May be overkill for very small components

Real-World Examples

  • <select> and <option> HTML pattern
  • React Router (<Routes> and <Route>)
  • UI libraries like Radix UI or Chakra UI use this heavily (e.g., <Menu>, <MenuItem>)

Interview Tip

If they ask:

“Why use compound components?” You can answer: It gives consumers control over layout and structure without losing state synchronization. It avoids long prop lists and keeps components focused.


One-liner Summary

Compound components are multiple React components that work together, sharing implicit state through context, giving the parent control over behavior and the consumer control over layout.