Composition

Build complex UIs by combining small, focused components.

Composition means building bigger components out of smaller ones. React strongly favors composition over inheritance — you almost never extend components; you nest and combine them.

Patterns

  • Pass components as children for generic containers.
  • Pass components as props (sometimes called slots) for named regions like a header or sidebar.

Small, single-purpose components are easier to name, test, and reuse.

Example

Example · javascript
function Page({ sidebar, children }) {
  return (
    <div className="layout">
      <aside>{sidebar}</aside>
      <main>{children}</main>
    </div>
  );
}

function App() {
  return (
    <Page sidebar={<nav>Menu</nav>}>
      <h1>Dashboard</h1>
    </Page>
  );
}

When to use it

  • A page builder assembles Header, Sidebar, ContentArea, and Footer components together inside a PageLayout component instead of putting all markup in one monolithic file.
  • A chart dashboard composes ChartTitle, ChartLegend, and ChartCanvas into a ReportCard component so each part can be tested and updated independently.
  • A form library exposes a Form component that accepts Field, Label, and ErrorMessage children, letting callers compose the exact form shape they need.

More examples

Compose a page from sections

Composes four independent section components into a page without any shared logic leaking between them.

Example · jsx
import Navbar from './Navbar';
import HeroBanner from './HeroBanner';
import FeatureGrid from './FeatureGrid';
import Footer from './Footer';

function HomePage() {
  return (
    <>
      <Navbar />
      <HeroBanner />
      <FeatureGrid />
      <Footer />
    </>
  );
}

Slot-based composition

Accepts named slot props for header, body, and footer so the caller controls each region independently.

Example · jsx
function Dialog({ header, body, footer }) {
  return (
    <div role="dialog" className="dialog">
      <div className="dialog__header">{header}</div>
      <div className="dialog__body">{body}</div>
      <div className="dialog__footer">{footer}</div>
    </div>
  );
}

// Usage
// <Dialog
//   header={<h2>Confirm delete</h2>}
//   body={<p>This cannot be undone.</p>}
//   footer={<><CancelBtn /><DeleteBtn /></>}
// />

Specialised component via composition

Creates a specialised SaveButton by composing the generic IconButton — no class inheritance required.

Example · jsx
function IconButton({ icon, label, ...rest }) {
  return (
    <button className="icon-btn" aria-label={label} {...rest}>
      <span className="icon" aria-hidden="true">{icon}</span>
      <span className="label">{label}</span>
    </button>
  );
}

function SaveButton(props) {
  return <IconButton icon="💾" label="Save" {...props} />;
}

Discussion

  • Be the first to comment on this lesson.