Composition Over Configuration

Children and Slots Beat Booleans

Composition Over Configuration

When a component grows a forest of `showX` booleans, redesign it as a container whose pieces the caller composes.

4 min read Level 2/5 #react#patterns#composition
What you'll learn
  • Recognize "configuration soup"
  • Refactor toward `children` + slot props
  • Compound components — `Card.Header`, `Card.Body`

A component with too many boolean props (showHeader, showClose, useCompactLayout, …) is hard to read, hard to extend, and tends to grow forever. The fix: turn it into a container whose internals the caller composes.

The Smell

<Modal
  showClose
  showHeader
  title="Delete this?"
  showCancel
  cancelLabel="No"
  showOk
  okLabel="Yes"
  okKind="danger"
/>

Every new variant adds another prop. The API balloons.

The Refactor — Compound Components

function Modal({ onClose, children }) {
  return (
    <div className="modal" role="dialog">
      <button onClick={onClose} aria-label="Close">×</button>
      {children}
    </div>
  );
}
Modal.Header = function ModalHeader({ children }) {
  return <header>{children}</header>;
};
Modal.Body = function ModalBody({ children }) {
  return <div className="modal__body">{children}</div>;
};
Modal.Footer = function ModalFooter({ children }) {
  return <footer>{children}</footer>;
};

The caller composes the pieces:

<Modal onClose={close}>
  <Modal.Header>Delete this?</Modal.Header>
  <Modal.Body>This action can't be undone.</Modal.Body>
  <Modal.Footer>
    <Button onClick={close}>No</Button>
    <Button kind="danger" onClick={confirm}>Yes</Button>
  </Modal.Footer>
</Modal>

Adding a new section is a new sub-component, not a new prop. Removing one is just deleting JSX.

Slot Props

Sometimes you want named regions, not stacked children:

function Layout({ nav, sidebar, children }) {
  return (
    <div className="layout">
      <header>{nav}</header>
      <aside>{sidebar}</aside>
      <main>{children}</main>
    </div>
  );
}

<Layout nav={<TopNav />} sidebar={<UserMenu />}>
  <Article />
</Layout>

nav and sidebar are slot props — they take JSX directly.

When Configuration Is Right

Some props really ARE configuration — a Button with size="md" | "lg" is fine. The smell starts when you have 5+ booleans that toggle whole regions of the UI. At that point, composition wins.

Up Next

A pattern question that comes up constantly — should this component own its own state, or let the parent control it?

Controlled vs Uncontrolled →