Children
Provides helpers for counting, mapping and flattening the opaque children prop.
Children.count(children)
Children.forEach(children, fn, thisArg?)
Children.map(children, fn, thisArg?)
Children.only(children)
Children.toArray(children)Parameters
| Parameter | Type | Description |
|---|---|---|
$children | React.ReactNode | The value of the `children` prop your component received. Every method takes this as its first argument. |
$fn | (child: ReactNode, index: number) => ReactNode | Callback for map and forEach, called with each child and a zero-based index. For map it must return a React node. |
$thisArgoptional | any= undefined | The `this` value for fn in map and forEach. |
Return value
number | Array<ReactNode> | ReactElement | undefinedDepends on the method: `count` returns a number, `map` and `toArray` return a flat array of nodes, `only` returns the single element, `forEach` returns undefined. `map` returns `children` unchanged when it is null or undefined.
Errors
Children.only throws if children is not exactly one React element — including when it is an array containing a single element.
The children prop is deliberately opaque. It may be a single element, a string, a number, false, an array, or nested arrays from a .map(), so children.length and children.map() are wrong roughly as often as they are right. These helpers normalise all of that.
When to reach for it
Chiefly in older class-based code, and in generic layout components that must count or wrap whatever they are given — a list that numbers its rows, a toolbar that inserts separators, a wrapper that enforces exactly one child. Children.map also merges the keys it generates with the caller's keys, so reordered children keep their identity; a hand-rolled loop does not do that.
What trips people up
Traversal is one level deep and stops at element boundaries. A <Fragment> child counts as one item and its contents are never visited, so wrapping three rows in a fragment turns Children.count from 3 into 1. You also cannot see what a child renders — only the element describing it.
React itself calls this API fragile. Prefer an explicit array prop, several named slots, or a render prop when you control the component's API.
Example
When to use it
- Number or separate the rows of a generic list component
- Refuse to render unless exactly one child element was passed
- Add an index prop to every child in older class-based code
Frequently asked questions
How do I loop over props.children in React?
Use Children.map(children, fn) rather than children.map, because children may be a single element, a string, or nested arrays rather than a flat array.
Why does Children.count return 1 for a Fragment with several elements inside?
Traversal never descends into an element, and a Fragment is an element. The children inside it belong to the Fragment's own props, so they are not counted.
What is the difference between Children.toArray and Children.map?
toArray flattens children into an array and drops null, undefined and booleans without transforming anything, while map also applies your callback and merges the keys it produces with the original ones.
More examples
Inserting separators between children
Renders `Home / Docs / Children` with a separator after every child except the last. The count is needed up front because the callback has no other way to know which item is final.
import { Children } from 'react';
function Breadcrumbs({ children }) {
const last = Children.count(children) - 1;
return (
<p>
{Children.map(children, (child, i) => (
<>
{child}
{i < last ? ' / ' : ''}
</>
))}
</p>
);
}
export default function App() {
return (
<Breadcrumbs>
<a href="/">Home</a>
<a href="/docs">Docs</a>
<span>Children</span>
</Breadcrumbs>
);
}Requiring exactly one child
The button renders with a title attribute. Adding a second child, or wrapping the button in an array, makes Children.only throw immediately with a clear error rather than failing later inside cloneElement.
import { Children, cloneElement } from 'react';
function Tooltip({ label, children }) {
// Throws if given zero, two, or an array of children
const child = Children.only(children);
return cloneElement(child, { title: label });
}
export default function App() {
return (
<div>
<Tooltip label="Saves your work">
<button>Save</button>
</Tooltip>
</div>
);
}Why the array prop is usually better
FragileRows reports 1 row because the Fragment counts as a single child, while Rows correctly reports 2. This is the failure mode that makes React recommend an explicit data prop over children introspection.
// Fragile: breaks as soon as a caller wraps children in a Fragment,
// a conditional, or another component.
import { Children } from 'react';
function FragileRows({ children }) {
return <p>{Children.count(children)} rows</p>;
}
// Robust: the data is explicit and cannot be hidden by markup.
function Rows({ items }) {
return (
<div>
<p>{items.length} rows</p>
<ul>
{items.map((item) => (
<li key={item.id}>{item.label}</li>
))}
</ul>
</div>
);
}
export default function App() {
const items = [
{ id: 'a', label: 'Alpha' },
{ id: 'b', label: 'Beta' },
];
return (
<div>
<FragileRows>
<>
<span>Alpha</span>
<span>Beta</span>
</>
</FragileRows>
<Rows items={items} />
</div>
);
}
Discussion