DEV Community

Alexandra
Alexandra

Posted on

🧠 React.ReactNode vs JSX.Element vs React.ReactElement – What's the Damn Difference?

If you’re working with TypeScript and React, you’ve probably seen types like JSX.Element, React.ReactNode, and React.ReactElement floating around. Maybe you’ve even thrown one in just to make the red squiggle go away. 😬

🤔 So… What Are These Types?

Type What..? When..?
JSX.Element What JSX like compiles to When returning from a React component
React.ReactElement The object returned by React.createElement When you need type + props of a JSX node
React.ReactNode Anything React can render Use for children or render content

Now, let's dig deep.

1. JSX.Element – The Immediate Output of JSX

When you write something like:

const element = <h1>Hello, world!</h1>;
Enter fullscreen mode Exit fullscreen mode

The type of this element is JSX.Element. That’s what the JSX compiles to under the hood: a JavaScript object representing that virtual DOM node.

const MyComponent = (): JSX.Element => {
  return <span>I am a JSX.Element</span>;
};
Enter fullscreen mode Exit fullscreen mode

🔍 Use JSX.Element when you're typing a component return value. It’s the default. The safe bet. Your vanilla latte.

2. React.ReactElement – JSX with Metadata

A ReactElement is a more concrete object. It includes:

  • The type of component (e.g. 'div' or MyComponent)
  • The props passed to it
  • Potentially, keys and refs
const element: React.ReactElement = React.createElement('p', null, 'Hey there');
Enter fullscreen mode Exit fullscreen mode

🔍 Use React.ReactElement when you’re dealing with the React element object itself, not what you return from a component.

React.ReactNode – The Big Daddy of Renderables

This one’s wild. React.ReactNode can be:

  • A JSX.Element
  • ReactElement
  • A string
  • A number
  • null, undefined
  • false (yes, false!)
  • Arrays of all the above
  • A fragment or a portal

It represents anything React can render, making it the go-to for children props or any UI content.

Example:

type MyProps = {
  children: React.ReactNode;
};

const Wrapper = ({ children }: MyProps) => (
  <div className="wrapper">{children}</div>
);
Enter fullscreen mode Exit fullscreen mode

So you can do this:

<Wrapper>
  <h1>Hello</h1>
  Just some text
  {[<span key="1">One</span>, <span key="2">Two</span>]}
</Wrapper>
Enter fullscreen mode Exit fullscreen mode

🔍 Use React.ReactNode when accepting anything renderable as a prop. Especially children.

🧠 When to Use What?

  • Use JSX.Element when defining the return type of your functional component.
  • Use React.ReactNode when accepting children or rendering content.
  • Use React.ReactElement when dealing with React elements as objects, e.g. for rendering engines, inspection, or cloning.

🧙‍♀️ Bonus: Inspect a ReactElement

If you're building tooling (hello, component docs or previewers), you might want to peek into the props:

function debug(el: React.ReactElement) {
  console.log("Component type:", el.type);
  console.log("Props:", el.props);
}
Enter fullscreen mode Exit fullscreen mode

🔚 Closing Thoughts

Knowing the difference makes your components more robust, your APIs cleaner, and your mental model of React deeper.

So next time you hit children: any, stop. Breathe. And reach for React.ReactNode.

📚 References

  1. TypeScript Handbook – JSX
  2. https://www.typescriptlang.org/docs/handbook/jsx.html

  3. React Type Definitions (DefinitelyTyped GitHub)

  4. ReactNode definition: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts#L69

  1. React Docs – JSX In Depth
  2. https://reactjs.org/docs/jsx-in-depth.html

  3. React Docs – React.createElement

  4. https://reactjs.org/docs/react-api.html#createelement

  5. “React Children Type in TypeScript” by Kent C. Dodds

  6. https://kentcdodds.com/blog/how-to-type-react-children

Top comments (0)