How to Use React Component with Children

When I build admin portals and employee dashboards, I rarely want every card, panel, or page section to have fixed content. A reusable React component should provide the shared structure while letting each screen place its own headings, tables, forms, or buttons inside it.

That is exactly what a React component with children solves. The children prop lets a parent component pass JSX between a component’s opening and closing tags, making layouts flexible without repeating markup.

In this guide, you will build a reusable Chicago team dashboard panel and learn how to use a React component with children in real projects.

What Are React Component Children?

A React component is a reusable JavaScript function that returns JSX. JSX looks similar to HTML, but React uses it to describe what the browser should render.

The special children prop contains anything nested inside a component when you use it. For example, the <DashboardPanel> component below receives the heading, paragraph, and button placed between its tags.

<DashboardPanel>
<h2>Today’s Tasks</h2>
<p>Emily Johnson has 3 tasks due today.</p>
<button>View tasks</button>
</DashboardPanel>

React passes the nested JSX to DashboardPanel as a prop named children. This is useful when the outer layout stays the same but the inner content changes.

Think of a reusable panel like a gift box:

  • The DashboardPanel component creates the box, border, spacing, and background.
  • The children prop is whatever you place inside the box.
  • Each dashboard area can use the same box with different content.

If you are still getting comfortable with component structure, see this guide on setting up your first React application. It helps you understand where files such as App.jsx and main.jsx fit in a React project.

Create a React Component with Children

For this tutorial, use a modern Vite React project. You need a current Node.js installation before running these commands.

Open a terminal in the folder where you want to create the project, then run:

npm create vite@latest react-children-dashboard
cd react-children-dashboard
npm install
npm run dev

These commands create a React project, move into the project folder, install dependencies, and start a local development server. Vite shows a local address in your terminal. Open that address in the browser.

Next, replace the starter files with the code below.

Add the React entry file

The main.jsx file finds the root element in index.html and tells React to render the App component inside it.

src/main.jsx

import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import App from "./App";
import "./index.css";

createRoot(document.getElementById("root")).render(
<StrictMode>
<App />
</StrictMode>
);

The browser loads App as the main screen. The CSS import applies the dashboard styling to the full application.

Create the reusable panel component

Create a components folder inside src. Then create a file named DashboardPanel.jsx. The key line is {children}. It tells React where the nested content should appear inside the reusable panel.

src/components/DashboardPanel.jsx

function DashboardPanel({ title, children }) {
return (
<section className="dashboard-panel">
<div className="panel-header">
<h2>{title}</h2>
</div>

<div className="panel-content">
{children}
</div>
</section>
);
}

export default DashboardPanel;

You can refer to the screenshot below to see the output.

React Component with Children

This component accepts two props:

  • title is regular data passed to the component.
  • children is the JSX placed between <DashboardPanel> and </DashboardPanel>.

The component owns the shared section, heading area, spacing, and CSS class names. The parent component controls what appears in the panel body. This is a clean pattern for report cards, customer portal widgets, settings sections, and modal bodies.

For another practical props example, you can learn how props work in React.

Use children from App.jsx

Now use the reusable component several times. Each instance has a different title and different nested JSX.

src/App.jsx

import DashboardPanel from "./components/DashboardPanel";

function App() {
return (
<main className="app">
<header className="page-header">
<p className="eyebrow">Chicago Operations</p>
<h1>Team Task Dashboard</h1>
<p>
Track current work, team updates, and open requests for the Chicago
office.
</p>
</header>

<div className="dashboard-grid">
<DashboardPanel title="Today’s Tasks">
<p className="task-count">3 tasks due today</p>

<ul className="task-list">
<li>Review Denver sales report</li>
<li>Update Seattle customer notes</li>
<li>Schedule Austin project meeting</li>
</ul>

<button className="primary-button">View all tasks</button>
</DashboardPanel>

<DashboardPanel title="Team Update">
<p>
Emily Johnson completed the quarterly inventory review at 10:30 AM.
</p>

<p>
Michael Brown is preparing the customer onboarding checklist.
</p>
</DashboardPanel>

<DashboardPanel title="Open Requests">
<div className="request-row">
<span>New laptop request</span>
<strong>Pending</strong>
</div>

<div className="request-row">
<span>Expense report approval</span>
<strong>In review</strong>
</div>

<div className="request-row">
<span>Seattle travel booking</span>
<strong>Approved</strong>
</div>
</DashboardPanel>
</div>
</main>
);
}

export default App;

When the browser opens, you will see a page titled Chicago Operations Team Task Dashboard with three matching panels:

Chicago Operations
Team Task Dashboard
Track current work, team updates, and open requests for the Chicago office.

Today’s Tasks
3 tasks due today
• Review Denver sales report
• Update Seattle customer notes
• Schedule Austin project meeting
[View all tasks]

Team Update
Emily Johnson completed the quarterly inventory review at 10:30 AM.
Michael Brown is preparing the customer onboarding checklist.

Open Requests
New laptop request Pending
Expense report approval In review
Seattle travel booking Approved

All three panels come from one component. React renders different nested content because each <DashboardPanel> receives different children.

Add the dashboard CSS

The component works without CSS, but this stylesheet makes the layout easy to understand in the browser.

src/index.css

:root {
font-family: Arial, Helvetica, sans-serif;
color: #172033;
background: #f4f7fb;
font-synthesis: none;
text-rendering: optimizeLegibility;
}

* {
box-sizing: border-box;
}

body {
margin: 0;
min-width: 320px;
}

button {
font: inherit;
}

.app {
width: min(1120px, calc(100% - 32px));
margin: 0 auto;
padding: 56px 0;
}

.page-header {
max-width: 720px;
margin-bottom: 32px;
}

.eyebrow {
margin: 0 0 10px;
color: #2563eb;
font-size: 0.85rem;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
}

h1 {
margin: 0;
font-size: clamp(2rem, 5vw, 3.25rem);
line-height: 1.1;
}

.page-header > p:last-child {
margin: 16px 0 0;
color: #526077;
font-size: 1.05rem;
line-height: 1.6;
}

.dashboard-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 20px;
}

.dashboard-panel {
overflow: hidden;
border: 1px solid #dce3ef;
border-radius: 14px;
background: #ffffff;
box-shadow: 0 8px 24px rgba(29, 43, 76, 0.08);
}

.panel-header {
padding: 18px 20px;
border-bottom: 1px solid #e8edf5;
background: #f8faff;
}

.panel-header h2 {
margin: 0;
font-size: 1.1rem;
}

.panel-content {
padding: 20px;
color: #3d4c66;
line-height: 1.55;
}

.panel-content p:first-child {
margin-top: 0;
}

.panel-content p:last-child {
margin-bottom: 0;
}

.task-count {
color: #1d4ed8;
font-size: 1.25rem;
font-weight: 700;
}

.task-list {
padding-left: 20px;
}

.task-list li {
margin-bottom: 10px;
}

.primary-button {
padding: 10px 14px;
border: 0;
border-radius: 8px;
color: #ffffff;
background: #2563eb;
cursor: pointer;
font-weight: 700;
}

.primary-button:hover {
background: #1d4ed8;
}

.request-row {
display: flex;
justify-content: space-between;
gap: 12px;
padding: 12px 0;
border-bottom: 1px solid #e8edf5;
}

.request-row:last-child {
padding-bottom: 0;
border-bottom: 0;
}

.request-row strong {
color: #1d4ed8;
white-space: nowrap;
}

@media (max-width: 800px) {
.dashboard-grid {
grid-template-columns: 1fr;
}
}

The page displays three responsive white cards. On a wide screen, they appear side by side. On a smaller screen, they stack vertically so the dashboard remains readable.

Use React Component with Children and State

A component with children becomes more useful when the parent controls state. State is data that can change while a person uses your app. The useState hook stores that changing data and asks React to render the updated interface.

In this example, a manager can show or hide task details inside a reusable panel. The panel does not need to know how the button works. It only displays the JSX it receives through children.

Replace src/App.jsx with the complete code below.

src/App.jsx

import { useState } from "react";
import DashboardPanel from "./components/DashboardPanel";

function App() {
const [showTasks, setShowTasks] = useState(false);

function toggleTasks() {
setShowTasks((currentValue) => !currentValue);
}

return (
<main className="app">
<header className="page-header">
<p className="eyebrow">Chicago Operations</p>
<h1>Team Task Dashboard</h1>
<p>
Review work assigned to Emily Johnson and the rest of the operations
team.
</p>
</header>

<div className="dashboard-grid">
<DashboardPanel title="Today’s Tasks">
<p className="task-count">3 tasks due today</p>

<button className="primary-button" onClick={toggleTasks}>
{showTasks ? "Hide task details" : "Show task details"}
</button>

{showTasks && (
<ul className="task-list">
<li>Review Denver sales report</li>
<li>Update Seattle customer notes</li>
<li>Schedule Austin project meeting</li>
</ul>
)}
</DashboardPanel>

<DashboardPanel title="Team Update">
<p>
Emily Johnson completed the quarterly inventory review at 10:30 AM.
</p>

<p>
Michael Brown is preparing the customer onboarding checklist.
</p>
</DashboardPanel>

<DashboardPanel title="Open Requests">
<div className="request-row">
<span>New laptop request</span>
<strong>Pending</strong>
</div>

<div className="request-row">
<span>Expense report approval</span>
<strong>In review</strong>
</div>

<div className="request-row">
<span>Seattle travel booking</span>
<strong>Approved</strong>
</div>
</DashboardPanel>
</div>
</main>
);
}

export default App;

When the page first loads, the first panel shows this:

Today’s Tasks
3 tasks due today
[Show task details]

You can refer to the screenshot below to see the output.

Use React Component with Children

After clicking Show task details, React updates the state. The browser then shows the three task items below the button. Clicking the button again hides the list.

The expression showTasks && (...) is conditional rendering. It means “render the task list only when showTasks is true.” The nested list is still passed as children, but the parent decides when it exists.

For more examples of click actions, read about handling React events. Event handlers are functions that run after actions such as clicks, typing, or form submissions.

Pro Tip: I keep layout components like DashboardPanel unaware of business rules whenever possible. The panel should handle spacing and structure, while the parent owns state, API data, and user actions. That separation makes a component far easier to reuse in a new dashboard.

Pass Multiple Types of Children

The children prop does not only accept plain text or one HTML element. You can pass headings, paragraphs, lists, buttons, forms, components, fragments, and expressions that render JSX.

For example, this customer profile panel receives a heading, a paragraph, and a nested component.

src/components/CustomerStatus.jsx

function CustomerStatus({ status }) {
return (
<p className={`status status-${status.toLowerCase()}`}>
Account status: {status}
</p>
);
}

export default CustomerStatus;

src/components/DashboardPanel.jsx

function DashboardPanel({ title, children }) {
return (
<section className="dashboard-panel">
<div className="panel-header">
<h2>{title}</h2>
</div>

<div className="panel-content">
{children}
</div>
</section>
);
}

export default DashboardPanel;

src/App.jsx

import CustomerStatus from "./components/CustomerStatus";
import DashboardPanel from "./components/DashboardPanel";

function App() {
return (
<main className="app">
<header className="page-header">
<p className="eyebrow">Austin Customer Portal</p>
<h1>Customer Account Overview</h1>
<p>Review account details before the scheduled support call.</p>
</header>

<div className="dashboard-grid">
<DashboardPanel title="Customer Details">
<h3>Olivia Davis</h3>
<p>Olivia manages purchasing for a retail team in Austin, Texas.</p>
<CustomerStatus status="Active" />
</DashboardPanel>

<DashboardPanel title="Upcoming Appointment">
<p>Thursday, 2:00 PM Central Time</p>
<p>Topic: New inventory reporting workspace</p>
<button className="primary-button">Open appointment</button>
</DashboardPanel>

<DashboardPanel title="Support Note">
<p>
Olivia asked for help exporting the monthly product availability
report.
</p>
</DashboardPanel>
</div>
</main>
);
}

export default App;

Add these styles at the end of src/index.css:

.panel-content h3 {
margin-top: 0;
color: #172033;
}

.status {
display: inline-block;
margin-bottom: 0;
padding: 6px 10px;
border-radius: 999px;
font-size: 0.9rem;
font-weight: 700;
}

.status-active {
color: #166534;
background: #dcfce7;
}

The browser shows three customer portal cards. In the first card, the CustomerStatus component renders a green badge that says:

Account status: Active

This approach is powerful because the reusable wrapper does not need a separate prop for every possible inner element. You can add a new form, chart component, table, alert, or nested widget without changing DashboardPanel.

Use Children with a Reusable Empty State

A practical use of a React component with children is an empty-state wrapper. A dashboard may show different messages when there are no tasks, no reports, or no customers. The layout remains consistent, but the action button and message change.

Create this complete reusable component.

src/components/EmptyState.jsx

function EmptyState({ title, children }) {
return (
<section className="empty-state">
<div className="empty-state-icon" aria-hidden="true">
✓
</div>

<h2>{title}</h2>

<div className="empty-state-content">
{children}
</div>
</section>
);
}

export default EmptyState;

Now use it in your application.

src/App.jsx

import EmptyState from "./components/EmptyState";

function App() {
return (
<main className="app">
<header className="page-header">
<p className="eyebrow">Seattle Sales Portal</p>
<h1>Saved Reports</h1>
<p>Create and organize reports for the Seattle sales team.</p>
</header>

<EmptyState title="No saved reports yet">
<p>
Michael Brown has not created any saved sales reports for this
workspace.
</p>

<button className="primary-button">Create your first report</button>
</EmptyState>
</main>
);
}

export default App;

Add this CSS at the end of src/index.css:

.empty-state {
max-width: 680px;
padding: 48px 28px;
border: 1px solid #dce3ef;
border-radius: 14px;
background: #ffffff;
text-align: center;
box-shadow: 0 8px 24px rgba(29, 43, 76, 0.08);
}

.empty-state-icon {
display: grid;
width: 52px;
height: 52px;
margin: 0 auto 18px;
place-items: center;
border-radius: 50%;
color: #1d4ed8;
background: #dbeafe;
font-size: 1.5rem;
font-weight: 700;
}

.empty-state h2 {
margin: 0;
color: #172033;
}

.empty-state-content {
margin-top: 14px;
color: #526077;
line-height: 1.6;
}

.empty-state-content .primary-button {
margin-top: 8px;
}

The browser displays a centered empty-state card with a checkmark icon, the heading No saved reports yet, a message about Michael Brown, and a Create your first report button.

Notice that EmptyState defines the shared visual structure. The parent supplies the message and action through children. This is more flexible than making props such as message, buttonText, buttonColor, and buttonLink for every variation.

Children vs Regular Props

Both props and children move data from a parent component to a child component. Use regular props for named values that affect the component. Use children for content that belongs inside the component’s layout.

Use caseBetter choiceExample
Set a panel headingRegular proptitle="Today’s Tasks"
Choose a color or sizeRegular propvariant="primary"
Insert a form, list, or tablechildren<DashboardPanel><form>...</form></DashboardPanel>
Insert several unrelated elementschildrenHeading, paragraph, button, and another component
Pass a callback functionRegular proponClose={handleClose}

Here is a complete example that uses both together.

src/components/NotificationCard.jsx

function NotificationCard({ title, tone = "info", children }) {
return (
<section className={`notification-card notification-${tone}`}>
<h2>{title}</h2>
<div>{children}</div>
</section>
);
}

export default NotificationCard;

src/App.jsx

import NotificationCard from "./components/NotificationCard";

function App() {
return (
<main className="app">
<header className="page-header">
<p className="eyebrow">New York Inventory Tracker</p>
<h1>Inventory Alerts</h1>
<p>Review items that need attention before the next warehouse shipment.</p>
</header>

<NotificationCard title="Low Stock Alert" tone="warning">
<p>Wireless scanners are below the reorder threshold.</p>
<p>Only 4 units remain in the New York warehouse.</p>
<button className="primary-button">Create purchase request</button>
</NotificationCard>
</main>
);
}

export default App;

Add this CSS at the end of src/index.css:

.notification-card {
max-width: 680px;
padding: 24px;
border-radius: 14px;
}

.notification-card h2 {
margin-top: 0;
}

.notification-warning {
border: 1px solid #facc15;
color: #713f12;
background: #fef9c3;
}

.notification-warning .primary-button {
background: #a16207;
}

.notification-warning .primary-button:hover {
background: #854d0e;
}

The browser shows a yellow warning card titled Low Stock Alert. The title and tone props control the card’s named settings. The paragraphs and button are its children.

If you need to pass data in several different ways, learn how to pass values to React components. Keeping named settings in props makes each component call easier to read.

Things to Keep in Mind

  • Render {children} intentionally: Place it exactly where nested JSX should appear. If you omit {children}, React receives the content but never displays it.
  • Use props for configuration: Keep values such as title, variant, isOpen, and event handler functions as named props instead of hiding them inside child markup.
  • Keep wrapper components focused: A panel should manage layout and styling, not fetch data, validate forms, and handle unrelated business rules.
  • Use semantic markup: Choose elements that fit the content, such as <section> for a grouped dashboard area, <button> for actions, and <form> for user input.
  • Avoid fragile child assumptions: Do not write a wrapper that expects children to always be one specific element unless you control every use of it.
  • Manage state in the right place: Keep state in the nearest common parent when several children need the same changing data. This makes component communication easier to follow.

Frequently Asked Questions

What is children in React?

children is a special prop that React automatically provides when JSX appears between a component’s opening and closing tags. It lets a reusable component render different inner content without changing its shared outer layout.

How do I pass children to a React component?

Wrap the content inside the component tags. For example, <DashboardPanel><p>Task details</p></DashboardPanel> passes the paragraph as the children prop to DashboardPanel.

Can a React component have multiple children?

Yes. A component can receive one or many nested JSX elements, such as headings, paragraphs, buttons, lists, and other components. React groups them so you can render them with {children}.

Can I pass props and children together in React?

Yes. This is often the best pattern. Use named props for configuration, such as a title or style variant, and use children for the flexible content inside the component.

Why are my React children not showing?

First, check that your component includes {children} inside its returned JSX. Also confirm that you used both an opening and a closing component tag instead of a self-closing tag such as <DashboardPanel />.

Does React component with children work in React 18?

Yes. The children prop works normally in React 18 and modern Vite projects. It works with functional components, state, event handlers, conditional rendering, and nested reusable components.

A React component with children gives you a simple way to reuse a layout while keeping its inner content open. Start with a small wrapper such as a panel or empty state, then add props only for the settings that truly need names. I hope you found this article helpful.

You May Also Like

Leave a Comment