DEV Community

Cover image for React Component Composition Design Pattern With Examples
Chhakuli Zingare for CreoWis

Posted on • Originally published at creowis.com

4 1 1 1 1

React Component Composition Design Pattern With Examples

As a developers, we’re constantly looking for ways to make our applications more maintainable, scalable, and reusable. One of the most powerful patterns to help achieve this is the Composite Component Pattern. It allows us to break down large, complex UIs into small, focused components that can be easily combined to create more dynamic layouts.

In this post, I’ll walk you through everything you need to know about the Composite Component Pattern in React, including real-world use cases, in-depth examples, and the best practices you should follow to maximize its effectiveness.

What Is the Composite Component Pattern?

In simple terms, the Composite Component Pattern is all about building small, focused components and then combining them to make bigger, more complex components. Instead of having huge components that try to do everything, you break things down into pieces that are easier to manage and reuse.

Think of it like building a car. Instead of designing the entire car as a single piece, you make parts like wheels, the engine, the seats, etc., and then assemble them into a full car. This gives you the flexibility to swap out parts, upgrade them, or reuse them in different cars.

By following this pattern, we end up with a more modular and easier-to-manage codebase.

Why Is It Useful in React?

1. Reusability: In large applications, having reusable components is a lifesaver. Components like Button, InputField, Modal, etc., can be used across different parts of the app, saving us time and reducing code duplication.

2. Maintainability: Smaller components are easier to manage. If there’s a bug in one part of your UI, you can pinpoint it faster without sifting through hundreds of lines of code.

3. Scalability: As your application grows, composing components to add new features is much easier than trying to modify an already large, complicated component.

Real-World Scenarios and Use Cases

To truly understand the power of the Composite component Pattern, let’s see how to build a Blog Page using the Composite Component Pattern with Next.js, TypeScript, and Tailwind CSS. We’ll look at how to break down the blog UI into smaller pieces, and how these pieces can be composed to create a dynamic and flexible blog page.

Step 1: Setting Up the Components

Our blog page will be composed of the following components:

1. Header — A navigation bar at the top of the page.

2. PostCard — A card that displays a single blog post’s title, excerpt, and a “Read More” link.

3. Pagination — Controls for navigating through multiple pages of blog posts.

4. BlogPage — The main component that ties everything together.

Let’s start by setting up the components.

1. Header Component

This component will render a simple navigation bar.

import React from 'react';
import Link from 'next/link';

const Header: React.FC = () => {
  return (
    <header className="bg-gray-800 p-4">
      <nav className="max-w-4xl mx-auto flex justify-between text-white">
        <Link href="/" className="text-2xl font-bold">
          My Blog
        </Link>
        <div>
          <Link href="/" className="px-4">
            Home
          </Link>
          <Link href="/about" className="px-4">
            About
          </Link>
          <Link href="/contact" className="px-4">
            Contact
          </Link>
        </div>
      </nav>
    </header>
  );
};

export default Header;
Enter fullscreen mode Exit fullscreen mode

The Header component is simple: it displays a navigation bar with links to different pages of the site.

2. PostCard Component

This component will display an individual blog post’s title, an excerpt, and a “Read More” link.

import React from 'react';
import Link from 'next/link';

interface PostCardProps {
  title: string;
  excerpt: string;
  id: string;
}

const PostCard: React.FC<PostCardProps> = ({ title, excerpt, id }) => {
  return (
    <div className="bg-white p-6 rounded-lg shadow-md mb-6">
      <h2 className="text-2xl font-bold mb-2">{title}</h2>
      <p className="text-gray-700 mb-4">{excerpt}</p>
      <Link href={`/post/${id}`} className="text-blue-500 hover:text-blue-700">
        Read More
      </Link>
    </div>
  );
};

export default PostCard;
Enter fullscreen mode Exit fullscreen mode

Each PostCard will receive three props: title, excerpt, and id. The “Read More” link will redirect the user to a separate page where they can read the full post.

3. Pagination Component

This component handles the pagination controls for navigating through multiple blog posts.

import React from 'react';
import Link from 'next/link';

interface PaginationProps {
  currentPage: number;
  totalPages: number;
}

const Pagination: React.FC<PaginationProps> = ({ currentPage, totalPages }) => {
  return (
    <div className="flex justify-center mt-8">
      {currentPage > 1 && (
        <Link href={`/?page=${currentPage - 1}`} className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">
          Previous
        </Link>
      )}
      <span className="mx-4 text-xl">{currentPage} / {totalPages}</span>
      {currentPage < totalPages && (
        <Link href={`/?page=${currentPage + 1}`} className="px-4 py-2 bg-blue-500 text-white rounded-md hover:bg-blue-600">
          Next
        </Link>
      )}
    </div>
  );
};

export default Pagination;
Enter fullscreen mode Exit fullscreen mode

The Pagination component displays the Previous and Next buttons and shows the current page number along with the total number of pages.

Step 2: Assembling the Blog Page

Now let’s assemble these components in the BlogPage component.

import React from 'react';
import Header from '../components/Header';
import PostCard from '../components/PostCard';
import Pagination from '../components/Pagination';

const BlogPage: React.FC = () => {
  // Sample data for posts
  const posts = [
    { id: '1', title: 'How to Learn React', excerpt: 'An easy guide to learning React in 2025.' },
    { id: '2', title: 'Mastering TypeScript', excerpt: 'A deep dive into the power of TypeScript.' },
    { id: '3', title: 'Building with Tailwind CSS', excerpt: 'Creating beautiful UIs with Tailwind CSS.' },
  ];

  const currentPage = 1; // Simulating the current page
  const totalPages = 3;  // Simulating the total number of pages

  return (
    <div>
      <Header />
      <main className="max-w-4xl mx-auto p-4">
        <h1 className="text-4xl font-bold mb-8 text-center">Welcome to My Blog</h1>
        {posts.map(post => (
          <PostCard key={post.id} title={post.title} excerpt={post.excerpt} id={post.id} />
        ))}
        <Pagination currentPage={currentPage} totalPages={totalPages} />
      </main>
    </div>
  );
};

export default BlogPage;
Enter fullscreen mode Exit fullscreen mode

Here’s how we use the components:

Header is rendered at the top.

• We map through the posts array and render a PostCard for each post.

Pagination is included at the bottom of the page to navigate between pages.

Best Practices for the Composite Component Pattern

When using the Composite Component Pattern, it’s important to follow some best practices to ensure that your code remains clean, efficient, and scalable.

1. Single Responsibility Principle (SRP)

Each component should have a single responsibility. If you find yourself adding more than one responsibility to a component, it’s a sign that it needs to be broken down into smaller components.

For example, if a component handles both UI and logic, it might be better to split it into separate presentational and container components.

2. Keep Components Small and Focused

Aim to create smaller components that do one thing well. This makes them easier to reuse, test, and maintain.

Bad: A UserProfile component that handles rendering the profile, updating the user data, and sending requests to the server.

Good: Separate components like ProfileHeader, ProfileForm, and ProfileButton that each have a clear, focused responsibility.

3. Leverage Context API and Hooks

For components that need to share state, avoid prop drilling by using React’s Context API. This allows your components to access shared data without passing it through every level of the component tree.

Advanced Use Cases for the Composite Component Pattern

While the Composite Component Pattern works great for simple UIs, it can also be used to build complex, dynamic applications that require highly customizable layouts.

1. Reusable Dashboard Widgets

In a dashboard application, you might have multiple widgets (charts, graphs, data tables, etc.). Using the Composite Component Pattern, each widget can be its own independent component, and the dashboard itself can be composed dynamically by combining different widgets.

2. Customizable Modal Dialogs

If you need to create modals with varying content (like confirmation modals, alert modals, or forms), you can create a generic Modal component that accepts children, so it can be dynamically populated with different content.

Conclusion

The Composite Component Pattern allows us to build clean, maintainable, and scalable UIs by breaking down complex components into smaller, reusable building blocks. By composing these blocks together, we can create flexible and dynamic UIs with ease.

In this example, we demonstrated how to use this pattern to build a blog page in Next.js with TypeScript and Tailwind CSS. We showed how the Header, PostCard, and Pagination components were combined to create a fully functional blog page.

By following the Composite Component Pattern, you can:

• Improve reusability by creating smaller, more focused components.

• Keep your code clean and maintainable.

• Make your app scalable and easy to extend.

Feel free to experiment with this in your own applications and explore how you can make your UI more modular and flexible.

Call to Action

If you found this blog post informative and valuable, we encourage you to visit other blogs on our page for more development tips, tutorials, and best practices.

Remember, writing code with the design pattern like this is an essential component of successful software development, especially in team environments. By embracing the right practices, you can set your team up for long-term success and deliver high-quality software that meets the evolving needs of your users.


We at CreoWis believe in sharing knowledge publicly to help the developer community grow. Let’s collaborate, ideate, and craft passion to deliver awe-inspiring product experiences to the world.

Let's connect:

This article is crafted by Chhakuli Zingare, a passionate developer at CreoWis. You can reach out to her on X/Twitter, LinkedIn, and follow her work on the GitHub.

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay