What is the difference between a React Node, Element, and Component?
A **Component** is the function or class you write (`function Button(){...}`). A **React Element** is a plain object describing what to render — what `<Button />` evaluates to: `{ type: Button, props: {...}, key, ref }`. A **React Node** is anything renderable: an element, a string, a number, null, false, or an array of these.
Three terms used loosely but with precise meanings.
Component
A function or class that returns UI. The 'thing you write'.
function Button({ children }: { children: ReactNode }) {
return <button>{children}</button>;
}
class Counter extends Component {
render() { return <div>...</div>; }
}A component is a template. It hasn't produced any UI yet.
React Element
The plain object returned by React.createElement (what JSX compiles to). It's a description of what to render — not the DOM, not the function output.
const el = <Button>Click</Button>;
// equivalent to:
const el = React.createElement(Button, null, 'Click');
// which is roughly:
// { type: Button, props: { children: 'Click' }, key: null, ref: null }Elements are immutable, cheap to create, and serializable.
React Node
The TypeScript type ReactNode — anything that can appear in JSX:
- React Element (
<div/>,<Button/>) - string or number (
'hello',42) - null, undefined, false (renders nothing)
- array of any of the above
- a Promise of any of the above (with Suspense)
- a Portal
type ReactNode =
| ReactElement
| string
| number
| boolean
| null
| undefined
| ReactNode[]
| Iterable<ReactNode>
| ReactPortal;Putting them together
function App() { // App is a Component
return ( // App returns a React Element
<div>
<Button>Click</Button>
Hello
{2 + 2}
{null}
</div>
);
}Why it matters
- Children typing: prop types should be
ReactNode, notReactElement.ReactElementexcludes strings and arrays. - JSX compiles to elements: when you see
React.createElementin compiled output, that's the element factory. - Components vs elements in props:
<Sidebar header={<Header/>} />passes an element;<Sidebar header={Header} />passes a component.
Common confusion
'A component is what gets rendered.'
Almost — a component is what describes what gets rendered. React calls the component, gets an element tree back, and then renders that to DOM.
'JSX returns HTML.'
No — JSX returns React elements (plain objects). React turns those into DOM during commit.
TypeScript quick reference
ReactNode // safest for children: anything renderable
ReactElement // only JSX-shaped objects, no strings/null
ComponentType<P> // the component itself (function or class)
JSX.Element // alias for ReactElement with default propsFollow-up questions
- •Why is ReactNode preferred over ReactElement for children prop typing?
- •What does React.createElement actually return?
- •Can you pass a component as a prop and render it inside?
Common mistakes
- •Typing children as ReactElement — excludes strings, numbers, arrays, null.
- •Confusing 'component' (the function) with 'element' (an instance description).
- •Mutating an element's props after creation — elements are immutable.
Performance considerations
- •Creating elements is cheap (plain object allocation). The cost is in calling components and diffing the element tree. Inline element creation in JSX has no measurable overhead compared to extracted variables.
Edge cases
- •Passing a component vs an element in props — different intent, different render call site.
- •React fragments are elements too; type is React.Fragment.
- •Portals are nodes but render into a DOM target outside the component tree.
Real-world examples
- •Compound components use the distinction: `<Tabs><Tabs.List>...</Tabs.List></Tabs>` — `Tabs.List` is a component, `<Tabs.List/>` is an element. Render-prop and slot APIs depend on knowing the difference.