The children prop is one of the most powerful features in React. It lets you pass JSX content between the opening and closing tags of a component, just like you nest HTML elements. This enables you to create flexible wrapper components, layouts, and complex component compositions. In this lesson, you'll learn everything about the children prop and how to use it to build more maintainable and reusable React applications.
What is the Children Prop?
In HTML, you can nest content inside tags:
<div>
<h1>Title</h1>
<p>Content goes here</p>
</div>In React, you can do the same thing with components using the children prop:
function Card(props) {
return (
<div className="card">
{props.children}
</div>
)
}
// Use it like HTML:
<Card>
<h1>Title</h1>
<p>Content goes here</p>
</Card>
// Everything between <Card> and </Card> becomes props.children!Whatever you put between the opening and closing tags automatically becomes available as props.children inside your component.
The children prop:
- Is a special prop automatically passed by React
- Contains everything between opening and closing tags
- Can be text, JSX elements, or other components
- Enables component composition and nesting
- Makes wrapper components possible
Basic Children Usage
Text Children
function Button(props) {
return (
<button className="btn">
{props.children}
</button>
)
}
// Text as children
<Button>Click Me</Button>
<Button>Submit Form</Button>
<Button>Cancel</Button>
// Each renders the text inside the buttonJSX Children
function Card(props) {
return (
<div className="card">
{props.children}
</div>
)
}
// JSX elements as children
<Card>
<h2>Card Title</h2>
<p>Card description goes here</p>
<button>Read More</button>
</Card>Component Children
function Container(props) {
return (
<div className="container">
{props.children}
</div>
)
}
function Header() {
return <header>Header Content</header>
}
function Footer() {
return <footer>Footer Content</footer>
}
// Components as children
<Container>
<Header />
<main>Main content</main>
<Footer />
</Container>Mixed Children
function Panel(props) {
return (
<div className="panel">
{props.children}
</div>
)
}
// Mix of text, elements, and components
<Panel>
<h3>Settings</h3>
Some text here
<SettingsForm />
<Button>Save</Button>
</Panel>Creating Wrapper Components
The children prop shines when creating wrapper components - components that wrap around other content and add behavior or styling:
Alert Component
function Alert({ type = 'info', children }) {
const colors = {
info: 'bg-blue-100 border-blue-500 text-blue-900',
success: 'bg-green-100 border-green-500 text-green-900',
warning: 'bg-yellow-100 border-yellow-500 text-yellow-900',
error: 'bg-red-100 border-red-500 text-red-900'
}
return (
<div className={`border-l-4 p-4 ${colors[type]}`}>
{children}
</div>
)
}
// Usage:
<Alert type="success">
<strong>Success!</strong> Your changes have been saved.
</Alert>
<Alert type="error">
<strong>Error!</strong> Something went wrong.
<button>Try Again</button>
</Alert>Modal Component
function Modal({ isOpen, onClose, children }) {
if (!isOpen) return null
return (
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={e => e.stopPropagation()}>
<button className="modal-close" onClick={onClose}>×</button>
{children}
</div>
</div>
)
}
// Usage:
<Modal isOpen={showModal} onClose={() => setShowModal(false)}>
<h2>Confirm Action</h2>
<p>Are you sure you want to continue?</p>
<button onClick={handleConfirm}>Confirm</button>
<button onClick={() => setShowModal(false)}>Cancel</button>
</Modal>Container Component
function Container({ maxWidth = '1200px', children }) {
return (
<div style={{
maxWidth: maxWidth,
margin: '0 auto',
padding: '0 20px'
}}>
{children}
</div>
)
}
// Usage:
<Container>
<Header />
<MainContent />
<Footer />
</Container>
<Container maxWidth="800px">
<Article />
</Container>Layout Components
Children are perfect for creating reusable layout components:
Split Layout
function SplitLayout({ left, right }) {
return (
<div className="split-layout">
<div className="split-left">
{left}
</div>
<div className="split-right">
{right}
</div>
</div>
)
}
// Usage with named props instead of children:
<SplitLayout
left={
<aside>
<Navigation />
</aside>
}
right={
<main>
<Content />
</main>
}
/>Grid Layout
function Grid({ columns = 3, gap = '20px', children }) {
return (
<div style={{
display: 'grid',
gridTemplateColumns: `repeat(${columns}, 1fr)`,
gap: gap
}}>
{children}
</div>
)
}
// Usage:
<Grid columns={3}>
<Card>Item 1</Card>
<Card>Item 2</Card>
<Card>Item 3</Card>
<Card>Item 4</Card>
<Card>Item 5</Card>
<Card>Item 6</Card>
</Grid>Section with Header
function Section({ title, subtitle, children }) {
return (
<section className="section">
<div className="section-header">
<h2>{title}</h2>
{subtitle && <p>{subtitle}</p>}
</div>
<div className="section-content">
{children}
</div>
</section>
)
}
// Usage:
<Section
title="Latest Products"
subtitle="Check out our newest arrivals"
>
<ProductGrid />
<ViewAllButton />
</Section>Manipulating Children
React provides utilities to work with children. You can check, transform, or modify them:
React.Children.map
function List({ children }) {
// Transform each child
return (
<ul className="list">
{React.Children.map(children, (child, index) => (
<li key={index} className="list-item">
{child}
</li>
))}
</ul>
)
}
// Usage:
<List>
<span>First item</span>
<span>Second item</span>
<span>Third item</span>
</List>
// Each span gets wrapped in an <li>React.Children.count
function TabPanel({ children }) {
const count = React.Children.count(children)
return (
<div className="tab-panel">
<p>This panel has {count} tabs</p>
{children}
</div>
)
}React.Children.only
function SingleChild({ children }) {
// Throws error if more than one child
const child = React.Children.only(children)
return (
<div className="single-child-wrapper">
{child}
</div>
)
}
// ✅ Works - one child
<SingleChild>
<div>Only child</div>
</SingleChild>
// ❌ Error - multiple children
<SingleChild>
<div>First</div>
<div>Second</div>
</SingleChild>Cloning Children with Additional Props
function ColoredList({ color, children }) {
return (
<div>
{React.Children.map(children, child => {
// Clone each child and add color prop
return React.cloneElement(child, { color: color })
})}
</div>
)
}
function Item({ color, children }) {
return <div style={{ color: color }}>{children}</div>
}
// Usage:
<ColoredList color="red">
<Item>First item</Item> {/* Will be red */}
<Item>Second item</Item> {/* Will be red */}
<Item>Third item</Item> {/* Will be red */}
</ColoredList>Conditional Rendering with Children
Only Render if Children Exist
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
{/* Only show content area if there are children */}
{children && (
<div className="card-content">
{children}
</div>
)}
</div>
)
}
// With children:
<Card title="Product">
<p>Description here</p>
</Card>
// Without children (no content area):
<Card title="Empty Product" />Default Content
function Panel({ children }) {
return (
<div className="panel">
{children || <p>No content provided</p>}
</div>
)
}
// With children:
<Panel>
<p>Custom content</p>
</Panel>
// Without children (shows default):
<Panel />Multiple Content Slots
Sometimes you want multiple "slots" for content. You can use named props alongside children:
Card with Header and Footer
function Card({ header, footer, children }) {
return (
<div className="card">
{header && (
<div className="card-header">
{header}
</div>
)}
<div className="card-body">
{children}
</div>
{footer && (
<div className="card-footer">
{footer}
</div>
)}
</div>
)
}
// Usage:
<Card
header={<h2>Card Title</h2>}
footer={<button>Action</button>}
>
<p>This is the main content in the middle.</p>
</Card>Dialog with Title and Actions
function Dialog({ title, actions, children }) {
return (
<div className="dialog">
<div className="dialog-title">
{title}
</div>
<div className="dialog-content">
{children}
</div>
<div className="dialog-actions">
{actions}
</div>
</div>
)
}
// Usage:
<Dialog
title="Confirm Delete"
actions={
<>
<button onClick={handleCancel}>Cancel</button>
<button onClick={handleDelete}>Delete</button>
</>
}
>
<p>Are you sure you want to delete this item?</p>
<p>This action cannot be undone.</p>
</Dialog>Children vs Regular Props
When should you use children vs regular props? Here's a guide:
Use Children When:
- The content is the main purpose of the component
- You want HTML-like syntax with opening/closing tags
- The content is complex or contains multiple elements
- You're building wrapper/container components
- The content varies significantly between uses
// ✅ Good use of children - complex content
<Card>
<h2>Title</h2>
<p>Description</p>
<Image src="..." />
<Button>Action</Button>
</Card>Use Regular Props When:
- The content is simple (single value or element)
- You need multiple distinct content areas
- The content needs a descriptive name
- You're passing configuration or data
// ✅ Good use of props - simple, named content
<Avatar
src="/user.jpg"
name="Alice"
status="online"
/>
// ✅ Good use of props - multiple content areas
<Dialog
title="Confirm"
content={<p>Are you sure?</p>}
actions={<Button>OK</Button>}
/>Common Patterns with Children
Composition Pattern
// Build complex UIs by composing simple components
function Page() {
return (
<Layout>
<Sidebar>
<Navigation />
<UserInfo />
</Sidebar>
<MainContent>
<Article />
<Comments />
</MainContent>
</Layout>
)
}Render Props Pattern
function DataFetcher({ url, children }) {
const [data, setData] = React.useState(null)
const [loading, setLoading] = React.useState(true)
React.useEffect(() => {
fetch(url)
.then(res => res.json())
.then(data => {
setData(data)
setLoading(false)
})
}, [url])
// Call children as a function with data
return children({ data, loading })
}
// Usage:
<DataFetcher url="/api/users">
{({ data, loading }) => (
loading ? <Spinner /> : <UserList users={data} />
)}
</DataFetcher>Slots Pattern
function Page({ header, sidebar, content, footer }) {
return (
<div className="page">
<header className="page-header">{header}</header>
<div className="page-body">
<aside className="page-sidebar">{sidebar}</aside>
<main className="page-content">{content}</main>
</div>
<footer className="page-footer">{footer}</footer>
</div>
)
}
// Clear structure with named slots
<Page
header={<AppHeader />}
sidebar={<Navigation />}
content={<Article />}
footer={<AppFooter />}
/>Common Children Mistakes
1. Forgetting to Render Children
// ❌ Wrong - children not rendered
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
{/* Forgot to put {children} here! */}
</div>
)
}
// ✅ Correct - render children
function Card({ title, children }) {
return (
<div className="card">
<h2>{title}</h2>
{children}
</div>
)
}2. Modifying Children Directly
// ❌ Wrong - don't modify children directly
function List({ children }) {
children.push(<li>Extra item</li>) // Error!
return <ul>{children}</ul>
}
// ✅ Correct - use React.Children utilities
function List({ children }) {
const items = React.Children.toArray(children)
return (
<ul>
{items}
<li>Extra item</li>
</ul>
)
}3. Expecting Children to Always Be Array
// ❌ Wrong - children isn't always an array
function List({ children }) {
return <ul>{children.map(...)}</ul> // Might error!
}
// ✅ Correct - use React.Children.map
function List({ children }) {
return (
<ul>
{React.Children.map(children, child => (
<li>{child}</li>
))}
</ul>
)
}4. Using Self-Closing Tag When You Need Children
// ❌ Wrong - self-closing tag has no children
<Card title="Hello" />
// ✅ Correct - use opening/closing tags for children
<Card title="Hello">
<p>Content goes here</p>
</Card>Key Takeaways
- Children is a special prop containing content between opening/closing tags
- Access children via
props.childrenin your component - Children can be text, JSX, components, or a mix
- Children enable component composition and wrapper components
- Use
React.Childrenutilities to work with children safely - Children are perfect for layout and container components
- Combine children with regular props for multiple content slots
- Use children when content is complex or the main purpose
- Use regular props when content is simple or needs a descriptive name
- Children can be functions (render props pattern)
- Always check if children exists before using conditional rendering
What's Next?
You now understand how to use the children prop to create flexible, composable components! You can build wrapper components, layouts, and complex component hierarchies.
But we've been writing props.children, props.title, props.name everywhere. Is there a cleaner way? Absolutely! In the next lesson, you'll learn about props destructuring - a technique that makes your code cleaner, more readable, and more professional. Get ready to level up your React skills! ✨