How to Use the Compound Components Pattern in React: From Prop Passing to Flexible UI

How to Use the Compound Components Pattern in React: From Prop Passing to Flexible UI
# Why React Code Sometimes Feels Messy — And How the Compound Components Pattern Can Help

## Introduction

Have you ever:

- Opened a React project and thought: *"Why is this code so messy?"*
- Tried adding a feature but felt you needed to **rewrite the component**?
- Struggled with managing **state** and **props** between a parent and its children?

If yes, you’re not alone. These frustrations affect countless React developers — but **React itself isn't to blame**.  
The culprit? Common **code smells**, such as:

- Props drilled down multiple layers  
- Bloated components that try to do everything  
- Duplicate logic scattered across files  
- Careless rendering causing performance hits  

---

## Understanding Code Smells in React

A **code smell** isn't broken code — it’s a warning that your design could cause long-term headaches. Symptoms include:

- Poor maintainability
- Low reusability
- Difficult scalability
- Complex debugging

---

## Why Use Design Patterns?

**Design Patterns** are proven, reusable solutions for common problems.  
Benefits in React include:

- Cleaner, more maintainable codebases
- Easier debugging and enhancements
- Better scalability
- Improved composability and reusability

---

## Introducing the Compound Components Pattern

One of the most powerful solutions for **prop-drilling hell** is the **Compound Components Pattern**:

- Lets related components **work together** without endless props  
- Builds naturally **composable UI** that shares context & state  
- Improves maintainability and flexibility

---

**Tip:** Mastering this pattern — and spotting code smells — can transform your architecture and developer experience.

For tutorial creators, platforms like [AiToEarn官网](https://aitoearn.ai/) let you **generate**, **publish**, and **monetize** programming content across Douyin, Kwai, WeChat, Bilibili, Facebook, Instagram, LinkedIn, YouTube, Pinterest, and X. You can even track [AI模型排名](https://rank.aitoearn.ai) to keep improving.

---

## Table of Contents

1. [React 19 Code Set Up](#react-19-code-set-up)  
2. [A Messy Modal Component](#a-messy-modal-component)  
3. [Problems with the Messy Modal](#issues-with-this-modal-implementation)  
4. [The Compound Components Pattern](#introducing-the-compound-components-pattern)  
5. [Building a Modal with Compound Components](#how-to-build-a-modal-component-using-the-compound-components-pattern)  
   - [Why Keep Subcomponents in the Same File](#why-didnt-we-create-separate-files-for-the-subcomponents)  
   - [Using the Modal](#how-to-use-the-modal-component)  
   - [Building an Accordion](#how-to-build-an-accordion-component-using-the-compound-components-pattern)  
   - [Embed Accordion in Modal](#adding-the-accordion-to-the-modal)  
6. [Use Cases](#the-use-cases)  
7. [Pitfalls & Anti-Patterns](#the-pitfalls-and-anti-patterns)  
8. [15 Days of React Design Patterns](#15-days-of-react-design-patterns)  
9. [Wrapping Up](#final-note)  

---

## React 19 Code Set Up

We'll start by setting up a React 19 environment so we can refactor messy code step-by-step.

**Source Code:** [GitHub repo](https://github.com/tapascript/15-days-of-react-design-patterns/tree/main/day-03/compound-components-patterns)

### Step 1 — Install Node.js

node -v

If not installed: [Download Node.js](https://nodejs.org/en/download) (v18+ recommended).

### Step 2 — Create React Project with Vite

npx degit atapas/code-in-react-19#main compound-components-pattern


### Step 3 — Install Dependencies

cd compound-components-pattern

npm install

or yarn install / pnpm install


### Step 4 — Open in Your Editor

![image](https://blog.aitoearn.ai/content/images/2025/10/img_001-8.png)

---

## A Messy Modal Component

Inside `src/messy/Modal.jsx`:

function Modal({ title, body, primaryAction, secondaryAction }) {

return (

{title}

{body}

{secondaryAction}

{primaryAction}

);

}

export default Modal;


Usage in `App.jsx`:

import Modal from "./messy/Modal";

import "./App.css";

function App() {

return (

title="Delete Account"

body="Are you sure you want to delete your account?"

primaryAction={Delete}

secondaryAction={Cancel}

/>

);

}

export default App;


Add styling in `App.css` for backdrop, header, footer, etc.

![image](images/img_003.png)

---

## Issues with This Modal Implementation

- **Rigid structure** — Hard to customize layout without adding multiple props  
- **Mixed responsibilities** — Layout + state handled together  
- **Poor reusability** — Can't use different content types easily  
- **Scalability limits** — Would need multiple component variations  
- **Testing challenges** — Strong coupling increases complexity  

---

## Introducing the Compound Components Pattern

![image](https://blog.aitoearn.ai/content/images/2025/10/img_004-4.png)

Think of it like LEGO:

- **Parent** = Base plate (provides structure & rules)
- **Children** = Lego pieces (can be arranged freely)
- No need for endless props — **just compose elements as needed**

---

## How to Build a Modal Component Using the Compound Components Pattern

### Step 1 — Structure

src/with-pattern/modal/Modal.jsx


### Step 2 — Implementation

const Modal = ({ children, isOpen, onClose }) => {

if (!isOpen) return null;

return (

{children}

);

};

function ModalHeader({ children }) { return

{children}; }

function ModalBody({ children }) { return

{children}; }

function ModalFooter({ children }) { return

{children}; }

Modal.Header = ModalHeader;

Modal.Body = ModalBody;

Modal.Footer = ModalFooter;

export default Modal;


---

## Why Didn’t We Create Separate Files for the Subcomponents?

- Used **only within** the `Modal` context  
- Small helper components unlikely to be reused elsewhere  
- Keeping them together improves **discoverability** and prevents misuse  

---

## How to Use the Modal Component

import { useState } from "react";

import Modal from "./with-pattern/modal/Modal";

import "./App.css";

function App() {

const [isOpen, setIsOpen] = useState(false);

return (

setIsOpen(true)}>Open Modal

setIsOpen(false)}>

Welcome!

This is a modal built with the Compound Component pattern.

setIsOpen(false)}>Close

);

}

export default App;


---

## How to Build an Accordion Component Using the Compound Components Pattern

`src/with-pattern/accordion/Accordion.jsx`:

import { useState } from "react";

function Accordion({ children }) { return

{children}; }

function AccordionItem({ title, children }) {

const [isOpen, setIsOpen] = useState(false);

return (

setIsOpen(!isOpen)}>

{title}

{isOpen &&

{children}}

);

}

Accordion.Item = AccordionItem;

export default Accordion;


### Basic Styling

.accordion-item {

margin-bottom: 0.5rem;

border: 1px solid #ddd; border-radius: 4px;

}

.accordion-title {

width: 100%; text-align: left; padding: 0.5rem;

font-weight: bold; cursor: pointer; background: #f9f9f9; border: none;

}

.accordion-content {

padding: 0.5rem; background: #fff;

}


---

## Adding the Accordion to the Modal

import { useState } from "react";

import Modal from "./with-pattern/modal/Modal";

import AccordionDemo from "./with-pattern/accordion/AccordionDemo";

import "./App.css";

function App() {

const [isOpen, setIsOpen] = useState(false);

return (

setIsOpen(true)}>Open Modal

setIsOpen(false)}>

Welcome!

This is a modal built with the Compound Component pattern.

Help!

setIsOpen(false)}>Close

);

}

export default App;


![image](https://blog.aitoearn.ai/content/images/2025/10/img_007-2.png)

---

## The Use Cases

Works best for:

- Modals
- Accordions
- Tabs
- Steppers
- Tables (`Table.Head`, `Table.Row`, `Table.Body`)

---

## The Pitfalls and Anti-Patterns

Avoid:

- Attaching unrelated subcomponents to a parent
- Using subcomponents out of context
- Overusing compound components unnecessarily

---

## 15 Days of React Design Patterns

This is part of the [**15 Days of React Design Patterns**](https://www.youtube.com/playlist?list=PLIJrr73KDmRyQVT__uFZvaVfWPdfyMFHC) series — covering essential React patterns to level up your skills.

---

## Final Note

The **Compound Components Pattern** enables:

- Clean composition of complex UIs
- Flexibility without endless props
- Better maintenance & scalability

For sharing your work widely, tools like [AiToEarn官网](https://aitoearn.ai/) connect **AI generation**, **multi-platform publishing**, analytics, and monetization into one open-source workflow — perfect for developers aiming to grow an audience while building sustainable income.

---

**Stay Connected:**
- [YouTube](https://www.youtube.com/tapasadhikary?sub_confirmation=1)  
- [Newsletter — The Commit Log](https://tapascript.substack.com/subscribe?utm_medium=fcc)  
- [LinkedIn](https://www.linkedin.com/in/tapasadhikary/)  
- [Discord](https://discord.gg/zHHXx4vc2H)  

Keep learning, keep building 🚀

Read more