Skip to main content

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

  • children is 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 children when the component wraps content; use regular props for named, specific data
  • In TypeScript, always declare children: React.ReactNode in your interface

Quick example

tsx
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:

tsx
// 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 array

Fix: use React.Children.toArray() to normalize:

tsx
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:

tsx
// 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:

tsx
// 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.tsx receives children to wrap every page with consistent UI
  • React Router - <Route> uses children to render nested routes
  • Material-UI - <Box>, <Card>, <Dialog> all accept children for flexible content
  • Compound components - <Tabs> and <TabPanel> coordinate through children

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:

tsx
function WithProp({ children, disabled }) { return React.Children.map(children, child => React.isValidElement(child) ? React.cloneElement(child, { disabled }) : child ); }

Examples

Layout component

tsx
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 shell

Page 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

tsx
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 only

React.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 ready
Premium

A concise answer to help you respond confidently on this topic during an interview.

Finished reading?