Compound Components: What, Why and When.

 (Updated)1 min read

What are Compound Components?

It's a base component that expects to be combined with other component parts. Below the <Multiselect /> is the base component and the <Option /> and <Group /> components are the composable parts.

<Multiselect
  selectedValues={[1, 2]}
  onSelectedValuesChange={newValues => /* ... */}/>
  <Option optionValue={1}>One</Option>
  <Group header="The best numbers">
    <Option optionValue={2}>Two</Option>
    <Option optionValue={3}>Three</Option>
  </Group>
</Multiselect>

It differs from the use of { children } props where you are not expecting any components in particular.

<Box>
  <Header title="My Work" />
  <Content>Lots of good stuff</Context>
</Box>

While the <Multiselect /> children will accept any components, having a combination of a base and a part component like <Option /> that is intended to be used with it passes our Compound Component definition.

Why would you opt for this pattern?

The main advantage that the Compound Component pattern version offers is its flexibility. Want to make a <Multiselect /> of people that includes their avatar? Easy.

<Multiselect
  selectedValues={[1, 2]}
  onSelectedValuesChange={newValues => /* ... */}/>
  <PersonOption personId={1}>Jane</Option>
  <PersonOption personId={2}>John</Option>
</Multiselect>

We can support many variations without having to change the base components code.

To mirror the same behaviour using strict props we need to start adding flags like isPersonOptions:

<Multiselect
  selectedValues={[1, 2]}
  onSelectedValuesChange={newValues => /* ... */}
  isPersonOptions={true}
  options={[
    {name: 'Jane', id: 1},
    {name: 'John', id: 2},
  ]}/>
</Multiselect>

More flags will build up over time and the complexity will grow.

When should you use it?

It's when you need flexibility. Are you building something that will be widely used?

See React Component API Design for API design alternatives.

Was this article helpful?