Component Composition in React

Component composition is one of the most important ideas in React. It allows you to build complex user interfaces by combining smaller, focused components instead of putting everything into one large component.

A React application can contain dozens or even hundreds of components. The real power comes from deciding how those components work together.

For example, a learning platform might contain:

  • Navbar
  • Sidebar
  • CourseCard
  • CourseList
  • LessonCard
  • ProgressBar
  • Button
  • Footer

Instead of creating one enormous component that handles the entire page, React lets you compose these smaller components into a complete interface.

function App() {
  return (
    <>
      <Navbar />
      <Sidebar />
      <CourseList />
      <Footer />
    </>
  );
}

Here, App is composed of several smaller components.

This is called component composition.

What Is Component Composition?

Component composition means building a larger component or interface by combining smaller components.

Think of components as building blocks.

A single block may not represent an entire structure, but multiple blocks can be combined to create something much larger.

For example:

App
├── Navbar
├── Sidebar
├── MainContent
│   ├── CourseList
│   │   ├── CourseCard
│   │   ├── CourseCard
│   │   └── CourseCard
│   └── Pagination
└── Footer

Each component has a specific responsibility.

The Navbar handles navigation.

The Sidebar handles sidebar navigation.

The CourseList handles the collection of courses.

The CourseCard displays an individual course.

The Footer handles the footer area.

Together, these components create the complete application interface.

Why Component Composition Matters

Without composition, applications can quickly become difficult to maintain.

Imagine putting an entire learning platform into a single component:

function App() {
  return (
    <div>
      {/* Navbar */}

      {/* Sidebar */}

      {/* Course list */}

      {/* Course cards */}

      {/* Progress section */}

      {/* Footer */}

      {/* More UI */}
    </div>
  );
}

As the application grows, this component can become thousands of lines long.

That creates several problems:

  • It becomes harder to understand.
  • Finding specific UI becomes difficult.
  • Changes can affect unrelated parts.
  • Reusing UI becomes harder.
  • Testing becomes more complicated.
  • Debugging takes longer.

Composition solves this by allowing you to divide the interface into meaningful components.

function App() {
  return (
    <>
      <Navbar />
      <CourseDashboard />
      <Footer />
    </>
  );
}

The implementation details are moved into smaller components.

Components Can Be Composed Together

A component can contain other components.

For example:

function CourseDashboard() {
  return (
    <main>
      <CourseList />
      <ProgressSummary />
    </main>
  );
}

Then CourseList can contain CourseCard components.

function CourseList() {
  return (
    <section>
      <CourseCard />
      <CourseCard />
      <CourseCard />
    </section>
  );
}

The composition can continue through multiple levels.

App
└── CourseDashboard
    ├── CourseList
    │   ├── CourseCard
    │   ├── CourseCard
    │   └── CourseCard
    └── ProgressSummary

This structure makes the application easier to reason about.

Parent and Child Components

Composition naturally creates parent-child relationships.

For example:

function App() {
  return <CourseDashboard />;
}

Here, App is the parent of CourseDashboard.

Then:

function CourseDashboard() {
  return (
    <main>
      <CourseList />
      <ProgressSummary />
    </main>
  );
}

CourseDashboard becomes the parent of CourseList and ProgressSummary.

This creates a component hierarchy.

App
└── CourseDashboard
    ├── CourseList
    └── ProgressSummary

Understanding this hierarchy becomes especially important when you start working with props and state.

Composition Through Props

Components can also be composed by passing data through props.

Consider a reusable CourseCard:

function CourseCard({ title, instructor }) {
  return (
    <article>
      <h2>{title}</h2>
      <p>Instructor: {instructor}</p>
    </article>
  );
}

A parent component can compose multiple cards using different data.

function CourseList() {
  return (
    <section>
      <CourseCard
        title="React Fundamentals"
        instructor="John"
      />

      <CourseCard
        title="JavaScript Essentials"
        instructor="Sarah"
      />
    </section>
  );
}

The same component is used multiple times, but each instance receives different data.

This is an important combination:

Composition + Props = reusable UI structures

Composition Through Children

One of the most powerful composition techniques in React is the children prop.

Consider this component:

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

You can place other components or JSX inside it.

function App() {
  return (
    <Card>
      <h2>React Course</h2>
      <p>Learn React from beginner to advanced.</p>
    </Card>
  );
}

The content between <Card> and </Card> becomes the children prop.

Conceptually:

Card
└── children
    ├── h2
    └── p

This makes the Card component flexible.

The Card doesn’t need to know exactly what content it will contain.

Understanding the children Prop

Consider:

function Container({ children }) {
  return (
    <div className="container">
      {children}
    </div>
  );
}

Now you can use it with different content.

<Container>
  <h2>Welcome</h2>
</Container>

Or:

<Container>
  <CourseList />
</Container>

Or:

<Container>
  <Profile />
  <Settings />
</Container>

The container provides the structure while the parent decides what content goes inside it.

This separation is one of the core ideas behind composition.

Composition vs Hardcoding

Consider a component that hardcodes its content:

function Card() {
  return (
    <div className="card">
      <h2>React Course</h2>
      <p>Learn React.</p>
    </div>
  );
}

This works, but the component is tightly connected to one particular piece of content.

A more flexible approach is:

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}

Now the parent controls the content.

<Card>
  <h2>React Course</h2>
  <p>Learn React.</p>
</Card>

<Card>
  <h2>JavaScript Course</h2>
  <p>Learn JavaScript.</p>
</Card>

The same Card component can support both.

Component Composition with Layout Components

Composition is especially useful for layouts.

For example:

function PageLayout({ children }) {
  return (
    <div className="page-layout">
      <Navbar />

      <main>
        {children}
      </main>

      <Footer />
    </div>
  );
}

Now different pages can use the same layout.

function HomePage() {
  return (
    <PageLayout>
      <h1>Welcome to Web4Learners</h1>
    </PageLayout>
  );
}

Another page can use the same layout:

function CoursesPage() {
  return (
    <PageLayout>
      <CourseList />
    </PageLayout>
  );
}

Another page could contain:

function ProfilePage() {
  return (
    <PageLayout>
      <Profile />
    </PageLayout>
  );
}

The layout stays consistent while the page-specific content changes.

Composition with Multiple Props

Composition does not always require only children.

You can pass different components through props.

For example:

function DashboardLayout({ sidebar, content }) {
  return (
    <div className="dashboard">
      <aside>
        {sidebar}
      </aside>

      <main>
        {content}
      </main>
    </div>
  );
}

Then:

function App() {
  return (
    <DashboardLayout
      sidebar={<Sidebar />}
      content={<CourseList />}
    />
  );
}

This allows the parent to control different areas of the layout.

However, don’t automatically use this pattern everywhere. In many cases, children or a normal component hierarchy is simpler and easier to understand.

Composition with Header and Footer

A common layout pattern looks like this:

function Layout({ children }) {
  return (
    <>
      <Header />

      <main>
        {children}
      </main>

      <Footer />
    </>
  );
}

Then:

function App() {
  return (
    <Layout>
      <HomePage />
    </Layout>
  );
}

The resulting structure is conceptually:

Layout
├── Header
├── children
│   └── HomePage
└── Footer

This is a simple but very common example of composition.

Composition and Reusability

Composition makes reusable components much more useful.

Suppose you create a reusable Button:

function Button({ children }) {
  return (
    <button className="button">
      {children}
    </button>
  );
}

You can now use it with different content:

<Button>
  Start Course
</Button>
<Button>
  Login
</Button>
<Button>
  View Profile
</Button>

The component controls the button structure while the parent controls its content.

You can also combine composition with props:

function Button({ children, type }) {
  return (
    <button className={`button ${type}`}>
      {children}
    </button>
  );
}

Usage:

<Button type="primary">
  Start Learning
</Button>

The component provides reusable behavior and structure while props provide customization.

Composition vs Inheritance

React generally encourages composition instead of inheritance for sharing UI structure and behavior.

In object-oriented programming, inheritance might be used to create relationships between classes.

For example:

BaseComponent
     ↓
SpecialComponent

React components are generally composed instead:

Page
├── Header
├── Sidebar
├── Content
└── Footer

Instead of creating a specialized component by inheriting from another component, you typically combine components together.

For example:

function DashboardPage() {
  return (
    <Layout>
      <Dashboard />
    </Layout>
  );
}

The components cooperate through composition rather than an inheritance hierarchy.

A Practical Learning Platform Example

Imagine you are building a course page.

The page might contain:

CoursePage
├── CourseHeader
├── CourseDescription
├── LessonList
│   ├── LessonItem
│   ├── LessonItem
│   └── LessonItem
├── InstructorCard
└── CourseActions

You could compose these components like this:

function CoursePage() {
  return (
    <main>
      <CourseHeader />
      <CourseDescription />
      <LessonList />
      <InstructorCard />
      <CourseActions />
    </main>
  );
}

Then:

function LessonList() {
  return (
    <section>
      <LessonItem />
      <LessonItem />
      <LessonItem />
    </section>
  );
}

And:

function LessonItem({ title }) {
  return (
    <article>
      <h3>{title}</h3>
    </article>
  );
}

Now the page is assembled from smaller components.

Composition with Data

Composition becomes even more powerful when combined with arrays and .map().

For example:

const courses = [
  {
    id: 1,
    title: "React Fundamentals"
  },
  {
    id: 2,
    title: "JavaScript Essentials"
  },
  {
    id: 3,
    title: "CSS Mastery"
  }
];

The parent can compose a list of reusable cards:

function CourseList() {
  return (
    <section>
      {courses.map((course) => (
        <CourseCard
          key={course.id}
          title={course.title}
        />
      ))}
    </section>
  );
}

The structure becomes:

CourseList
├── CourseCard
├── CourseCard
└── CourseCard

But the cards are generated from data.

This approach is extremely common in real React applications.

Composition Does Not Mean Making Everything a Component

A common beginner mistake is thinking that every small piece of JSX must become a separate component.

For example, this is usually unnecessary:

function Title() {
  return <h2>React Course</h2>;
}

If the title is simple and used only once, keeping it inside its parent may be clearer:

function CourseCard() {
  return (
    <article>
      <h2>React Course</h2>
      <p>Learn React.</p>
    </article>
  );
}

Create a component when there is a useful reason, such as:

  • The UI is reused.
  • The UI has its own responsibility.
  • The component has meaningful logic.
  • The component makes the parent easier to understand.
  • The component needs independent state.
  • The component represents a meaningful part of the interface.

The goal is not to create the maximum number of components.

The goal is to create a clear and maintainable component structure.

A Good Component Composition Structure

A well-composed application might look like this:

App
├── Header
├── MainLayout
│   ├── Sidebar
│   └── Content
│       ├── PageHeader
│       ├── CourseList
│       │   ├── CourseCard
│       │   ├── CourseCard
│       │   └── CourseCard
│       └── Pagination
└── Footer

Each level has a clear purpose.

App assembles the major sections.

MainLayout manages the main page structure.

CourseList manages the collection.

CourseCard manages an individual course.

This makes the component tree easier to understand.

Common Mistakes with Component Composition

Creating One Giant Component

Putting the entire application into App makes the code difficult to maintain.

Instead of:

function App() {
  // hundreds of lines
}

break meaningful sections into components.

Creating Too Many Tiny Components

Avoid extracting every <div> or <p> into its own component without a reason.

Over-componentization can make simple code harder to follow.

Making Components Too Dependent on Each Other

A component should avoid knowing unnecessary implementation details about its children.

Pass information through props and composition instead.

Hardcoding Content That Should Be Flexible

If a reusable component always contains the same content, consider whether children or props would make it more flexible.

Confusing Composition with Duplication

Using a component multiple times is not duplication.

For example:

<CourseCard />
<CourseCard />
<CourseCard />

is composition using reusable components.

The implementation exists once, while the component can appear many times.

Best Practices for Component Composition

Keep Components Focused

A component should have a clear responsibility.

For example:

CourseCard

should primarily represent a course card rather than handling the entire course page.

Compose from Meaningful Components

Prefer:

<CourseHeader />
<LessonList />
<InstructorCard />

when these represent meaningful parts of your UI.

Use Props for Customization

Use props when a component needs different data or behavior.

<CourseCard
  title="React"
  instructor="Alex"
/>

Use children for Flexible Content

When the component provides a wrapper or structure around arbitrary content, children is often a natural choice.

<Card>
  <CourseDetails />
</Card>

Keep the Component Tree Understandable

When someone looks at:

<App>
  <Header />
  <CoursePage />
  <Footer />
</App>

they should be able to understand the application’s structure quickly.

Component Composition Cheat Sheet

ConceptMeaning
CompositionCombining components to build larger UI
ParentComponent that renders another component
ChildComponent rendered by a parent
PropsData passed from parent to child
childrenContent placed inside a component
ReusabilityUsing the same component in multiple places
Layout componentComponent responsible for page structure
Component treeHierarchical structure of components

A useful mental model is:

Small Components
       ↓
Composition
       ↓
Larger Components
       ↓
Complete Interface

Practice Exercise

Create a small learning dashboard using component composition.

Create these components:

App
├── Header
├── Dashboard
│   ├── WelcomeMessage
│   ├── CourseList
│   │   ├── CourseCard
│   │   ├── CourseCard
│   │   └── CourseCard
│   └── ProgressCard
└── Footer

Your App should compose the major sections:

function App() {
  return (
    <>
      <Header />
      <Dashboard />
      <Footer />
    </>
  );
}

Then compose the dashboard:

function Dashboard() {
  return (
    <main>
      <WelcomeMessage />
      <CourseList />
      <ProgressCard />
    </main>
  );
}

Finally, make CourseCard reusable by passing the course information through props.

Try creating at least three different course cards from the same component.

Image Placement

Place an image immediately after the section “What Is Component Composition?”

Create a modern 16:9 React infographic showing component composition as a visual hierarchy.

The visual should show:

React Application
       ↓
    App
       ↓
 ┌─────┼─────┐
Header Main Footer
        ↓
   CourseList
    ↓  ↓  ↓
  Card Card Card

Use a modern developer-focused interface with React-inspired visual elements, clean cards, subtle connectors, and a polished contemporary design. Keep text minimal so the image works well as an educational illustration.

Caption: Component composition lets React applications grow by combining smaller reusable components.

Alt text: React component composition showing an application built from nested reusable components.

Key Takeaways

  • Component composition means combining smaller components to build larger interfaces.
  • Components can contain other components.
  • Composition creates parent-child relationships.
  • Props allow components to be customized with data.
  • The children prop allows flexible content to be placed inside a component.
  • Layout components are a common and useful composition pattern.
  • React generally favors composition rather than inheritance.
  • Composition improves organization, reuse, and maintainability.
  • Not every piece of JSX needs to become a component.
  • Good composition creates a component tree that is easy to understand.
  • Combining composition with props and arrays makes React interfaces highly reusable.

The central idea to remember is simple:

Don’t build the entire interface as one component. Build smaller meaningful components and compose them together.

Leave a Comment