React

children as a prop: the implicit slot

children is a prop like any other, with a fixed position in the markup: React fills it from the element content and the component places it.

Key points

  • JSX turns the element content into the children prop, not a separate channel.
  • The right type is ReactNode, which includes strings, numbers, null and arrays.
  • Spreading props that carry children silently replaces the children already there.

children is a prop like any other, with a fixed position in the markup: React fills it with the element content and the component decides where to place it.

Where the value comes from

<Panel>text</Panel> becomes createElement(Panel, null, "text"), and the third argument arrives in props.children. Writing children="text" gives the same result: the syntax changes, the data does not.

The right type

In TypeScript the type is ReactNode, not string and not JSX.Element: it accepts text, numbers, null, fragments and arrays of nodes.

type PanelProps = {
  title: React.ReactNode;
  children: React.ReactNode;
};

function Panel({ title, children }: PanelProps) {
  return (
    
      {title}
      {children}
    
  );
}

With string the component rejects an element; with JSX.Element it rejects plain text. ReactNode is the union that matches what React really accepts inside a container.

More than one slot

When there are two or three regions, explicit names beat children: header and footer read well at the call site and do not depend on order.

function Card({ header, children, footer }) {
  return (
    
      {header && {header}}
      {children}
      {footer && {footer}}
    
  );
}

children stays the unnamed slot, the one the caller fills without thinking. Everything else gets a name, because a name is free documentation at the point of use.

The silent failure

A component that renders <div {...props} /> and then <div>{children}</div> breaks in two ways: the spread carries the children prop too, replacing the children already there, and the second container stays empty. Types do not help, because both shapes are valid.

The command

Type checking children is TypeScript work; the command installs the React types and checks the project without emitting files.

npm install --save-dev typescript @types/react
npx tsc --noEmit

Live records in the catalogue

Three records that use children as content: dialog takes the modal body, nested-dialog nests a second dialog inside the first, accordion-05 takes one element per panel. They are records among the 111,985 components in the catalogue.

Source and licence

React and @types/react ship under the MIT licence. The React documentation page on passing props describes children as an ordinary prop, and the TypeScript cheat sheet names ReactNode for children.

The limitation

The type does not force you to pass anything: children: React.ReactNode also accepts an absent value, so an empty panel compiles and produces a container with no content. When content is required you need a runtime check or a narrower type.

Where to continue

The general model is in what React is; why an identical children value avoids a render is in React.memo; the comparison with Svelte 5 snippets is in Svelte 5 snippets.

Frequently asked questions

Is children required?

No, unless the type says so. React passes undefined when the element has no content, so the component either handles that case or declares the prop as required.

Can I read children as an array?

Not directly: children can be a single node, a string or an array. To count or map it, use React.Children.toArray, which normalises the shapes.

Is it wrong to pass children to a nested element?

No, that is how a wrapper is built: the component receives the children and places them. It becomes a bug when a prop spread overwrites them and nobody notices.

What is the difference between children and the children prop?

None: JSX fills the children prop with the element content. Writing children={...} explicitly is equivalent and useful when the value is a variable.

Does a change in children remount the component?

No, it updates the prop and React reconciles the children. The subtree remounts only when the element type or the key changes.