The children prop
So far our components were self-closing: <TaskItem />. But HTML tags wrap content, <div>content</div>, and components can too. Whatever you put between a component's opening and closing tags arrives as a special prop named children:
function Card({ title, children }) { return ( <section className="card"> <h2>{title}</h2> {children} </section> ); } function App() { return ( <Card title="Weather"> <p>Sunny, 24°C</p> <p>No rain expected.</p> </Card> ); }
The two paragraphs become children and render where {children} appears. Card does not know or care what is inside it.
Why children matters
children lets you build wrapper components: cards, modals, page layouts, styled panels. The wrapper owns the frame, the caller owns the content. This is the same separation you get from higher-order functions in Advanced JavaScript, where a function receives behavior as an argument instead of hard-coding it.
Typical wrappers in real apps:
<Layout>wraps every page with a nav bar and footer<Modal>wraps any content in an overlay dialog<Button>wraps a label or icon in consistent styling
One wrapper, unlimited contents.
Wrappers in plain JavaScript
children is just a parameter holding already-rendered content. panel puts a heading above its children, and layout puts a nav above and a footer below.
function panel(title, children) { return "<section><h2>" + title + "</h2>" + children + "</section>"; } function layout(children) { return "<nav>Home</nav>" + children + "<footer>Made with React</footer>"; } console.log(layout(panel("Weather", "<p>Sunny</p>"))); console.log(layout("<p>Not found</p>"));
Output
<nav>Home</nav><section><h2>Weather</h2><p>Sunny</p></section><footer>Made with React</footer> <nav>Home</nav><p>Not found</p><footer>Made with React</footer>
Each function returns one string with the children dropped into the middle, and neither one inspects what it was handed. layout concatenates whatever arrives, which is exactly what makes it reusable.
The second log is the payoff. layout wraps any content, a whole panel or a bare paragraph, without knowing which it received, so adding a third kind of page needs no change to layout at all.
The first log shows nesting, since panel(...) is evaluated first and its returned string becomes layout's argument. In JSX that reads as <Layout><Panel title="Weather">...</Panel></Layout>, and the nesting is delivered through the children prop rather than through an explicit call.
Note that panel takes title and children as separate parameters, which mirrors the JSX version's { title, children }. The difference is that JSX fills children from what sits between the tags while title comes from an attribute, and in plain JavaScript both are ordinary arguments.
Reading a children-based component
function Shout({ children }) { return <strong>{children}!!!</strong>; } root.render(<Shout>Ship it</Shout>);
The screen shows Ship it!!! in bold.
The text between <Shout> and </Shout> becomes the children prop, so {children} is the string "Ship it", and the component wraps it in <strong> with !!! appended.
Two expressions sit side by side inside the strong, being {children} and the literal text !!!. JSX allows any number of children in an element, so mixing an embedded expression with plain text is normal and needs no separator.
Note that Shout never mentions strings anywhere. Passing <Shout><em>Ship it</em></Shout> would work identically, wrapping an italic element in bold, because children holds whatever the caller put there.
Which prop holds nested content
For <Card title="Notes"><p>Hello</p></Card>, the <p>Hello</p> element arrives in the children prop.
Everything between a component's opening and closing tags is delivered as children, so Card receives { title: "Notes", children: <p>Hello</p> } and renders it wherever it places {children} in its JSX.
children is an ordinary prop with a reserved, automatic name, which is why Card destructures it alongside the others as { title, children }. You could even pass it explicitly as <Card title="Notes" children={<p>Hello</p>} />, and nobody writes that because the nesting syntax reads better.
One detail worth expecting: children is a single element when there is one child and an array when there are several. That matters the moment you try to count or map over it, and for the common case of simply rendering {children} in a slot, React handles both shapes without you noticing.