# React Component Props: JSX Element vs React Node vs React Element Explained

> Understand React component props: Discover the difference between JSX Element, React Node, and React Element. Learn when to use ReactNode for flexible content vs ReactElement for single instances.

- Repository: [Meta/react](https://github.com/facebook/react)
- Tags: deep-dive
- Published: 2026-02-16

---

**Use `ReactNode` for flexible props that accept any renderable content, and `ReactElement` (or `JSX.Element` in TypeScript) when you require a single, inspectable component instance.**

When defining React component props in TypeScript or Flow, choosing between `JSX.Element`, `ReactNode`, and `ReactElement` determines what values your components can accept and how strictly they validate incoming data. According to the facebook/react source code, these types represent distinct levels of specificity in React's rendering pipeline, from the broad union of all renderable values to the precise object shape created by JSX factories.

## Understanding React Node in React Component Props

The `ReactNode` type represents the broadest set of values that React can render. Defined in [`packages/shared/ReactTypes.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js), it is a union type encompassing every possible renderable entity.

```javascript
// packages/shared/ReactTypes.js
export type ReactNode =
  | React$Element<any>   // a React element (see React Element below)
  | ReactPortal
  | ReactText
  | ReactFragment
  | ReactProvider<any>
  | ReactConsumer<any>;

```

**What ReactNode includes:**

- **React$Element**: The base React element type
- **ReactPortal**: Elements rendered into different DOM containers
- **ReactFragment**: Arrays or iterables of ReactNodes (used for `<>…</>` syntax)
- **ReactText**: Primitive strings and numbers
- **ReactProvider/ReactConsumer**: Context API elements

Use `ReactNode` for React component props that must accept any renderable value, such as `children`, `icon`, or `header` slots. This flexibility allows callers to pass strings, numbers, elements, fragments, or arrays without type errors.

## Understanding React Element in React Component Props

The `ReactElement` type represents the specific object shape created when JSX is compiled or when `React.createElement` is called. Defined in [`packages/shared/ReactElementType.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactElementType.js), this is the low-level representation that React's reconciler processes.

```javascript
// packages/shared/ReactElementType.js
export type ReactElement = {
  $$typeof: any,
  type: any,
  key: any,
  ref: any,
  props: any,
  _owner: any,
  _store: {validated: 0 | 1 | 2, ...},
  _debugInfo: null | ReactDebugInfo,
  _debugStack: Error,
  _debugTask: null | ConsoleTask,
};

```

**Key characteristics of ReactElement:**

- Always contains `type`, `props`, `key`, and `ref` fields
- Created by the JSX factory functions in [`packages/react/src/jsx/ReactJSXElement.js`](https://github.com/facebook/react/blob/main/packages/react/src/jsx/ReactJSXElement.js)
- Represents a single, concrete element instance

Use `ReactElement` for React component props when you require exactly one element and need to inspect its properties, clone it, or ensure it is not plain text. This is common for render props or component injection patterns where you need to call `React.cloneElement` or access `element.type`.

## JSX Element vs React Element in TypeScript

In TypeScript projects, `JSX.Element` serves as the canonical alias for the value returned by JSX expressions. While `ReactElement` is the runtime type defined in React's source, `JSX.Element` is the TypeScript-specific interface that describes what the JSX factory produces.

**TypeScript usage:**

```typescript
type ButtonProps = {
  /** Render any component that behaves like an <a> */
  as: JSX.Element;
};

```

**Flow usage (React's internal codebase):**

```javascript
type ButtonProps = {
  as: React$Element<any>,
};

```

Both resolve to the same underlying `ReactElement` shape implemented in [`packages/shared/ReactElementType.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactElementType.js). The distinction is primarily semantic: `JSX.Element` signals TypeScript context, while `ReactElement` signals the runtime object structure.

## Choosing the Right Type for React Component Props

Selecting the appropriate type depends on the contract you want to enforce. Use this decision matrix when defining React component props:

| Desired flexibility | Recommended type | Use case |
|---------------------|------------------|----------|
| Any renderable value | `ReactNode` | Children slots, content props that accept strings, numbers, fragments, or elements |
| Exactly one element | `ReactElement` or `JSX.Element` | Component injection, render props requiring cloneElement, or when inspecting element.type |
| Array of elements | `ReactElement[]` or `ReactNode[]` | Lists where you specifically want multiple items |

**General rule:** Default to `ReactNode` for React component props unless you have a specific reason to restrict the input to a single element object.

## Practical Code Examples

### Accepting Any Renderable Node

Use `ReactNode` when your component needs to accept flexible content:

```tsx
// src/components/Alert.tsx
import { ReactNode } from 'react';

type AlertProps = {
  /** The message can be a string, number, element, or fragment */
  message: ReactNode;
};

export function Alert({ message }: AlertProps) {
  return <div className="alert">{message}</div>;
}

```

This allows callers to pass `<Alert message="Saved!" />` or `<Alert message={<strong>Saved!</strong>} />` without type errors.

### Requiring a Single Element

Use `ReactElement` when you need to inspect or clone the element:

```tsx
// src/components/Panel.tsx
import { ReactElement, ReactNode, cloneElement } from 'react';

type PanelProps = {
  /** Must be a single React element (e.g., `<Header/>`) */
  header: ReactElement;
  children: ReactNode;
};

export function Panel({ header, children }: PanelProps) {
  // Safe to access header.type or clone because we know it's an element
  return (
    <section>
      <header>{cloneElement(header, { className: 'panel-header' })}</header>
      <main>{children}</main>
    </section>
  );
}

```

Calling `<Panel header="Title" />` produces a type error, enforcing that callers must pass `<Panel header={<Title />} />`.

### Using JSX.Element in TypeScript

For TypeScript projects specifically targeting the JSX factory return type:

```tsx
// src/components/Link.tsx
import { cloneElement } from 'react';

type LinkProps = {
  /** Render any component that behaves like an <a> */
  as: JSX.Element;
  href: string;
};

export function Link({ as, href }: LinkProps) {
  // We can safely clone the element because JSX.Element guarantees an element shape
  return cloneElement(as, { href });
}

```

## Key Source Files in the React Repository

Understanding these types requires examining the actual source code in the facebook/react repository:

| File | Description | GitHub Link |
|------|-------------|-------------|
| [`packages/shared/ReactTypes.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js) | Flow definitions for `ReactNode`, `ReactFragment`, `ReactText`, and other shared types | [View source](https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js) |
| [`packages/shared/ReactElementType.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactElementType.js) | The low-level `ReactElement` object shape with internal debugging fields | [View source](https://github.com/facebook/react/blob/main/packages/shared/ReactElementType.js) |
| [`packages/react/src/jsx/ReactJSXElement.js`](https://github.com/facebook/react/blob/main/packages/react/src/jsx/ReactJSXElement.js) | Implementation of the JSX runtime (`jsx`, `jsxs`, `jsxDEV`) that produces `ReactElement` objects | [View source](https://github.com/facebook/react/blob/main/packages/react/src/jsx/ReactJSXElement.js) |
| [`packages/react/src/__tests__/ReactCreateElement-test.js`](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/ReactCreateElement-test.js) | Test suite demonstrating how `React.createElement` produces `ReactElement` instances | [View source](https://github.com/facebook/react/blob/main/packages/react/src/__tests__/ReactCreateElement-test.js) |

## Summary

- **ReactNode** is the most flexible type for React component props, accepting strings, numbers, elements, fragments, arrays, and portals. Use it for `children` and content slots that need to support any renderable value.
- **ReactElement** represents the specific object created by JSX or `createElement`, containing `type`, `props`, `key`, and `ref` fields. Use it when you need to inspect, clone, or restrict a prop to a single component instance.
- **JSX.Element** is the TypeScript-specific alias for `ReactElement`, functionally equivalent but signaling TypeScript context. It is the idiomatic choice for TypeScript React component props.
- Default to `ReactNode` for most React component props unless you have a specific requirement to manipulate the element object or reject non-element values.

## Frequently Asked Questions

### What is the difference between ReactNode and ReactElement in React component props?

`ReactNode` is a union type defined in [`packages/shared/ReactTypes.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js) that includes primitives like strings and numbers, arrays, fragments, portals, and elements, making it suitable for props that accept any renderable content. `ReactElement` is a specific object type defined in [`packages/shared/ReactElementType.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactElementType.js) representing a single JSX element with `type`, `props`, `key`, and `ref` properties, which you use when you need to clone or inspect the element's structure.

### Should I use JSX.Element or ReactElement for TypeScript React component props?

Both types represent the same underlying structure, but `JSX.Element` is the idiomatic TypeScript choice as it directly corresponds to the return type of JSX expressions. `ReactElement` is more explicit about being a React-specific type and is often preferred when writing library code or when you need to specify generic parameters like `ReactElement<Props>`. For most application code, `JSX.Element` provides better interoperability with TypeScript's built-in JSX factory types.

### Why does ReactNode allow strings but ReactElement does not?

`ReactNode` explicitly includes `ReactText` (which covers strings and numbers) in its union definition found in [`packages/shared/ReactTypes.js`](https://github.com/facebook/react/blob/main/packages/shared/ReactTypes.js), because React's renderer can handle primitive values directly. `ReactElement` represents the specific object structure created by `React.createElement` or the JSX runtime in [`packages/react/src/jsx/ReactJSXElement.js`](https://github.com/facebook/react/blob/main/packages/react/src/jsx/ReactJSXElement.js), which always produces an object with `$$typeof`, `type`, and `props` fields—never a primitive string.

### When should I restrict a prop to ReactElement instead of using ReactNode?

Restrict a prop to `ReactElement` when your component logic depends on the element being an object with specific properties that you need to inspect or manipulate, such as when using `React.cloneElement` to inject additional props, or when you need to access `element.type` to determine the component type. This restriction prevents callers from passing plain strings or arrays that would cause runtime errors when your code attempts to treat them as element objects, enforcing at compile time that only single JSX expressions are provided.