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
DashboardPanelcomponent creates the box, border, spacing, and background. - The
childrenprop 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.

This component accepts two props:
titleis regular data passed to the component.childrenis 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.

After clicking Show task details, React updates the state. The b