In JSX expressions that contain both an opening tag and a closing tag, the content between those tags is passed as a special prop: props.children
. There are several different ways to pass children:
You can put a string between the opening and closing tags and props.children
will just be that string. This is useful for many of the built-in HTML elements. For example:
<MyComponent>
<h1>Hello world!</h1>
</MyComponent>
This is valid JSX, and props.children
in MyComponent will simply be <h1>Hello world!</h1>
.
Note that the HTML is unescaped, so you can generally write JSX just like you would write HTML.
Bare in mind, that in this case JSX:
You can provide more JSX elements as the children. This is useful for displaying nested components:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
You can mix together different types of children, so you can use string literals together with JSX children. This is another way in which JSX is like HTML, so that this is both valid JSX and valid HTML:
<div>
<h2>Here is a list</h2>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
Note that a React component can't return multiple React elements, but a single JSX expression can have multiple children. So if you want a component to render multiple things you can wrap them in a div
like the example above.
You can pass any JavaScript expression as children, by enclosing it within {}
. For example, these expressions are equivalent:
<MyComponent>foo</MyComponent>
<MyComponent>{'foo'}</MyComponent>
This is often useful for rendering a list of JSX expressions of arbitrary length. For example, this renders an HTML list:
const Item = ({ message }) => (
<li>{ message }</li>
);
const TodoList = () => {
const todos = ['finish doc', 'submit review', 'wait stackoverflow review'];
return (
<ul>
{ todos.map(message => (<Item key={message} message={message} />)) }
</ul>
);
};
Note that JavaScript expressions can be mixed with other types of children.
Normally, JavaScript expressions inserted in JSX will evaluate to a string, a React element, or a list of those things. However, props.children
works just like any other prop in that it can pass any sort of data, not just the sorts that React knows how to render. For example, if you have a custom component, you could have it take a callback as props.children
:
const ListOfTenThings = () => (
<Repeat numTimes={10}>
{(index) => <div key={index}>This is item {index} in the list</div>}
</Repeat>
);
// Calls the children callback numTimes to produce a repeated component
const Repeat = ({ numTimes, children }) => {
let items = [];
for (let i = 0; i < numTimes; i++) {
items.push(children(i));
}
return <div>{items}</div>;
};
Children passed to a custom component can be anything, as long as that component transforms them into something React can understand before rendering. This usage is not common, but it works if you want to stretch what JSX is capable of.
Note that false
, null
, undefined
, and true
are valid children. But they simply don't render. These JSX expressions will all render to the same thing:
<MyComponent />
<MyComponent></MyComponent>
<MyComponent>{false}</MyComponent>
<MyComponent>{null}</MyComponent>
<MyComponent>{true}</MyComponent>
This is extremely useful to conditionally render React elements. This JSX only renders a if showHeader
is true:
<div>
{showHeader && <Header />}
<Content />
</div>
One important caveat is that some "falsy" values, such as the 0
number, are still rendered by React. For example, this code will not behave as you might expect because 0
will be printed when props.messages
is an empty array:
<div>
{props.messages.length &&
<MessageList messages={props.messages} />
}
</div>
One approach to fix this is to make sure that the expression before the &&
is always boolean:
<div>
{props.messages.length > 0 &&
<MessageList messages={props.messages} />
}
</div>
Lastly, bare in mind that if you want a value like false
, true
, null
, or undefined
to appear in the output, you have to convert it to a string first:
<div>
My JavaScript variable is {String(myVariable)}.
</div>