isValidElement
Checks whether a value is a React element rather than a string, number, array or arbitrary object.
const isElement = isValidElement(value)Parameters
| Parameter | Type | Description |
|---|---|---|
$value | any | The value to test. Any type is accepted. |
Return value
boolean`true` if the value is a React element, `false` for anything else.
This answers one narrow question: was this value produced by a JSX tag or by createElement? Everything else is false.
Elements are not nodes
The distinction that catches people is element versus node. A React node is anything React can render — strings, numbers, arrays, portals, null, undefined, booleans, and elements. A React element is only the last of those. So isValidElement('Hello') and isValidElement([<div />, <div />]) are both false even though React renders both happily.
When to reach for it
Almost always as a guard in front of an API that only accepts elements — chiefly cloneElement, which throws on anything else. Since this.props.children routinely contains whitespace strings, conditional false values and numbers, wrapping the clone in this check is what stops a component from crashing on markup its author never anticipated.
What trips people up
A component function is not an element: isValidElement(MyComponent) is false, while isValidElement(<MyComponent />) is true. Portals from createPortal also return false. And a truthy result tells you nothing about what the element will render — it may still throw during rendering if its type is broken.
Example
When to use it
- Filter or clone only the real elements inside this.props.children
- Accept either an element or a plain string in a prop and branch on which arrived
- Validate a value before handing it to an API that only takes elements
Frequently asked questions
How do I check if props.children is a React element?
Test each child individually, not the children value itself — an array of elements returns false. Use Children.map or Children.toArray first, then call isValidElement on each item.
Does isValidElement work as a TypeScript type guard?
Yes. React's types declare it as `value is ReactElement`, so inside the true branch TypeScript narrows the value to ReactElement and lets you read `.type` and `.props`.
Why does isValidElement return false for a portal?
Portals created with createPortal are React nodes but not elements, so the check rejects them, as it does for strings, numbers, arrays, null and booleans.
More examples
Guarding a clone
The `showExtra &&` expression yields `false`, which reaches the map as a child. The guard lets it through unchanged instead of handing it to cloneElement, which would throw.
import { Children, cloneElement, isValidElement } from 'react';
function Item({ label, index }) {
return <li>{index}. {label}</li>;
}
function NumberedList({ children }) {
return (
<ol>
{Children.map(children, (child, i) =>
isValidElement(child) ? cloneElement(child, { index: i + 1 }) : child
)}
</ol>
);
}
export default function App() {
const showExtra = false;
return (
<NumberedList>
<Item label="First" />
{showExtra && <Item label="Conditional" />}
<Item label="Second" />
</NumberedList>
);
}A prop that accepts an element or a string
The first alert renders the bold element directly; the second wraps the plain string in brackets. One prop accepts both shapes because the check distinguishes them at render time.
import { isValidElement } from 'react';
function Alert({ icon, message }) {
return (
<p>
{isValidElement(icon) ? icon : <span>[{String(icon)}]</span>}{' '}
{message}
</p>
);
}
export default function App() {
return (
<div>
<Alert icon={<strong>!!</strong>} message="Element icon rendered as-is" />
<Alert icon="warn" message="String icon wrapped in brackets" />
</div>
);
}Why the check fails on a component reference
Only the JSX form is an element. The function reference is what ends up on `element.type`, which is how a parent can identify which component a child element describes.
import { isValidElement } from 'react';
function Button() {
return <button>Click</button>;
}
export default function Demo() {
const reference = Button; // the function itself
const element = <Button />; // an element describing it
return (
<ul>
<li>reference: {String(isValidElement(reference))}</li>
<li>element: {String(isValidElement(element))}</li>
<li>element.type === Button: {String(element.type === Button)}</li>
</ul>
);
}
Discussion