What is children in React
children is a special prop in React that automatically receives all JSX elements nested between a component's opening and closing tags.
Theory
TL;DR
childrenis populated automatically from nested JSX - you never pass it explicitly- Think of a component as a picture frame: the frame is the component, the picture is
children - Use
childrenwhen the component wraps content; use regular props for named, specific data - In TypeScript, always declare
children: React.ReactNodein your interface
Quick example
function Card({ children }) {
return <div className="card">{children}</div>;
}
// Everything between the tags becomes children
<Card>
<h1>Title</h1>
<p>Description</p>
</Card>
// Card renders both elements inside the div
// children = <h1>Title</h1><p>Description</p>When you nest JSX between component tags, React collects it and passes it as the children prop automatically. The component doesn't need to know what's inside. It just renders wherever you put {children}.
How it works internally
React converts JSX to function calls. <Card><h1>Title</h1></Card> becomes Card({ children: <h1>Title</h1> }). If you nest multiple elements, children becomes an array-like object. One element - it's that element directly. Multiple elements - it's an array. That asymmetry is the source of a common bug (see Common mistakes below).
When to use
Use children when:
- Building layout wrappers:
Page,Container,Section - Creating UI containers:
Card,Modal,Sidebar,Drawer - The component's job is to wrap content with styling or behavior
Skip children when you need multiple named slots. A Dialog with separate header, body, and footer is cleaner with explicit props, not one children blob.
Common mistakes
Assuming children is always an array:
// Crashes when you pass one child
function List({ children }) {
return <ul>{children.map(item => <li>{item}</li>)}</ul>;
}
<List><span>Single item</span></List> // children is a span, not an arrayFix: use React.Children.toArray() to normalize:
function List({ children }) {
const items = React.Children.toArray(children);
return <ul>{items.map((item, i) => <li key={i}>{item}</li>)}</ul>;
}Treating children as a string:
// Works for plain text, crashes for JSX
function Button({ children }) {
return <button>{children.toUpperCase()}</button>; // Crashes if children is <Icon />
}children can be a string, number, JSX element, array, or fragment. Never assume it's a plain string.
Forgetting types in TypeScript:
// TypeScript error - children not declared in interface
interface Props {
title: string;
}
function Card({ title, children }: Props) { // TS complains
return <div>{title}{children}</div>;
}
// Fix
interface Props {
title: string;
children: React.ReactNode;
}Real-world usage
- Next.js layouts -
_app.tsxreceiveschildrento wrap every page with consistent UI - React Router -
<Route>useschildrento render nested routes - Material-UI -
<Box>,<Card>,<Dialog>all acceptchildrenfor flexible content - Compound components -
<Tabs>and<TabPanel>coordinate throughchildren
Follow-up questions
Q: What's the difference between children and a regular prop like content?
A: children is populated automatically from nested JSX - you don't write children={...}. A regular prop requires explicit passing. Use children for wrapping content; use regular props for named, specific data.
Q: Can you pass multiple children?
A: Yes. Nest multiple elements and children becomes an array-like object containing all of them. Use React.Children.toArray() to iterate safely.
Q: How do you type children in TypeScript?
A: Use children: React.ReactNode for maximum flexibility. It accepts JSX elements, strings, numbers, fragments, and null. Use children: React.ReactElement only if you strictly need JSX with no strings.
Q: (Senior) How do you clone each child and inject a prop into all of them?
A: Use React.Children.map() with React.cloneElement(). Guard with React.isValidElement() to skip strings and numbers:
function WithProp({ children, disabled }) {
return React.Children.map(children, child =>
React.isValidElement(child)
? React.cloneElement(child, { disabled })
: child
);
}Examples
Layout component
function Page({ children, title }) {
return (
<div className="page">
<header>
<h1>{title}</h1>
</header>
<main className="page-content">
{children}
</main>
<footer>© 2026</footer>
</div>
);
}
export default function App() {
return (
<Page title="Dashboard">
<section>
<h2>Welcome</h2>
<p>Your stats here</p>
</section>
<section>
<h2>Recent activity</h2>
</section>
</Page>
);
}
// Both sections render inside main.page-content
// Page doesn't care what's inside - it just provides the shellPage handles the header, footer, and structure. Content changes without touching Page. In most Next.js projects, this pattern in the root layout is the first place developers actually see children doing something meaningful. That is the separation that makes components reusable.
Filtering children
function List({ children, filter }) {
const items = React.Children.toArray(children);
const filtered = filter
? items.filter(item => item.props.active !== false)
: items;
return (
<ul className="list">
{filtered.map((item, index) => (
<li key={index}>{item}</li>
))}
</ul>
);
}
<List filter={true}>
<span active={true}>Item 1</span>
<span active={false}>Item 2</span>
<span active={true}>Item 3</span>
</List>
// Renders Item 1 and Item 3 onlyReact.Children.toArray() normalizes children into a plain array regardless of whether it was a single element, an array, or a fragment. Without it, .filter() would crash on a single child.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.