AniUI Academy

Composition and Children

Building flexible components by passing other components in as children or props, rather than by trying to configure one giant component with an ever-growing list of options.

8 min read

You've already used children to build a generic Card wrapper. This lesson goes further: composition — building bigger components out of smaller, independent ones combined by the caller — is one of React's most important organizing ideas, and the alternative it avoids is worth seeing directly.

The problem composition avoids

Imagine a Panel component that started simple and grew a prop for every new variation someone needed:

function Panel({ title, showIcon, iconType, showFooter, footerText, showCloseButton }) {
  return (
    <div className="panel">
      <div className="panel-header">
        {showIcon && <Icon type={iconType} />}
        <h3>{title}</h3>
        {showCloseButton && <button>×</button>}
      </div>
      <div className="panel-body">{/* ...where does actual content go? */}</div>
      {showFooter && <div className="panel-footer">{footerText}</div>}
    </div>
  );
}

Every new use case adds another boolean and another prop, and Panel itself has to understand and branch on all of them, forever. This scales badly — the component becomes a small configuration language nobody enjoys reading.

The composition-based alternative

Instead, let Panel accept arbitrary content and only handle the structural parts it actually owns:

function Panel({ title, children }) {
  return (
    <div className="panel">
      <div className="panel-header"><h3>{title}</h3></div>
      <div className="panel-body">{children}</div>
    </div>
  );
}

Every caller composes whatever it needs by nesting content inside Panel, rather than describing it through props Panel has to know about in advance:

<Panel title="Settings">
  <SearchIcon />
  <SettingsForm />
  <button>Save</button>
</Panel>

Panel never needs to change again just because a new caller wants a slightly different combination of contents — it just renders whatever it's handed.

Multiple "slots" with named props

children is one generic slot. Sometimes a component genuinely has more than one distinct customizable area — an icon here, a footer there — and passing a whole element as a specifically-named prop covers that:

function PageLayout({ icon, children, footer }) {
  return (
    <div className="layout">
      <header>{icon}</header>
      <main>{children}</main>
      <footer>{footer}</footer>
    </div>
  );
}
 
<PageLayout
  icon={<SearchIcon />}
  footer={<p>© 2026 AniUI Academy</p>}
>
  <SettingsForm />
</PageLayout>

This is still composition, not configuration — PageLayout never inspects what icon or footer actually contain, it just places them. Compare that to a showIcon/iconType pair of props, where Panel itself would have had to know how to construct and render every possible icon.

Composition also solves the "wrapper hides children's state" problem

A subtler benefit: passing components in as children (rather than a parent trying to render them internally) means a re-render of the parent doesn't necessarily need to re-render — or discard the state of — whatever was passed in as children, since that JSX was created by the caller, not recreated fresh by the parent's own render. This becomes relevant once you're optimizing re-renders, later in this course; for now, the practical takeaway is simpler: prefer composing components together over growing one component's configuration surface indefinitely.

Try it yourself

Try it yourself
Loading playground...

What to remember

  • Prefer letting a component accept content via children (or a few named element props) over adding a new configuration prop for every new use case.
  • A prop can hold an entire React element, not just primitive values — useful when a component has several distinct customizable areas.
  • Composition keeps components generic and reusable; configuration-heavy components tend to grow an unmaintainable list of flags over time.

Check yourself

3 questions · pass 3/3 to unlock Context and useContext

up to 50
  1. 1.A Panel component grows a new boolean prop every time someone needs slightly different content inside it — showHeader, showFooter, showIcon, and so on. What's the composition-based alternative?

  2. 2.What does it mean to pass a component as a prop, rather than only ever using children?

  3. 3.Why is composition generally preferred over one large, heavily-configured component in React?

3 left to answer