How to Type the children Prop in React

Type the children prop with ReactNode for any JSX content or ReactElement for elements only. Learn the difference and the limits.

5 min read

Type the children prop with React.ReactNode when a component accepts any JSX content, or React.ReactElement when it should receive only elements. ReactNode is the broad, safe default for most wrappers. The type only controls what TypeScript accepts, not what the component renders.

Use ReactNode for flexible children

ReactNode covers every value that can appear between JSX tags: text, numbers, elements, arrays, and null. It is the right type for most wrapper components:

App.tsxApp.tsx
interface CardProps {
  children: React.ReactNode;
}
function Card({ children }: CardProps) {
  return (
    <section>
      {children}
    </section>
  );
}

The Card accepts a string, an element, or nothing as children. TypeScript lets all of those pass because ReactNode includes every possible child. This is why most design system wrappers type children as ReactNode.

Use ReactElement for elements only

ReactElement is narrower. It accepts JSX elements but rejects strings and numbers:

App.tsxApp.tsx
interface RowProps {
  icon: React.ReactElement;
  children: React.ReactNode;
}

Typing icon as ReactElement signals that the slot must be an element, not plain text. Choose it when a slot only makes sense with an actual element. ReactElement also includes arrays of elements, while excluding primitive text and numbers.

Children plus named slots

A component often mixes children with other slots. The icon is a named slot, and children holds the main content:

App.tsxApp.tsx
interface AlertProps {
  icon: React.ReactElement;
  children: React.ReactNode;
}
function Alert({ icon, children }: AlertProps) {
  return (
    <div className="alert">
      {icon} {children}
    </div>
  );
}

The named slot uses ReactElement because an icon should be an element, while children stays broad. This split is the common pattern for wrapper components, and it keeps each slot's intent readable at the call site.

What TypeScript cannot do

You cannot use TypeScript to require children of a specific element type, such as only li children. ReactNode and ReactElement are the two practical levels, and there is no type for a specific tag.

Keep children typed broadly and validate any stricter structure in code when it truly matters. A wrapper that is too picky about children is harder to compose. If you need a list that only accepts rows, build a dedicated Row component and compose it instead of fighting the type system.

Why the broad type is usually right

Most wrappers should accept anything. A Card that only accepts elements forces every caller to wrap a plain string in an element, which is noise. ReactNode avoids that friction.

Reserve ReactElement for slots where an element is genuinely required, like an icon or a badge that must render markup. The distinction is about intent, not safety.

What to learn next

See the broader props typing patterns in how to type React props, then revisit the children prop guide for the runtime composition side.

Rune AI

Rune AI

Key Insights

  • ReactNode accepts any JSX child content.
  • ReactElement accepts only JSX elements.
  • Use ReactNode for most wrappers.
  • Use ReactElement for slots that need an element.
  • TypeScript cannot require specific element children.
RunePowered by Rune AI

Frequently Asked Questions

What is the difference between ReactNode and ReactElement?

ReactNode is a broad union that includes text, numbers, arrays, elements, and null. ReactElement is narrower and accepts only JSX elements.

Can I require specific element children, like only li elements?

No. TypeScript cannot express a type for children of a specific element type. Use ReactNode or ReactElement, and validate any stricter structure in code.

Which type should I use for children?

Use React.ReactNode for most wrapper components, because it accepts any content a parent might nest. Use React.ReactElement only when a slot must be an element.

Conclusion

Type the children prop with React.ReactNode for any JSX content and React.ReactElement for elements only. ReactNode is the broad default, and TypeScript cannot restrict children to a specific element type.