isValidElement

Checks whether a value is a React element rather than a string, number, array or arbitrary object.

Signature
const isElement = isValidElement(value)

Parameters

ParameterTypeDescription
$valueanyThe 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

Try it yourself
Loading editor…
Loading React…

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.

Example · jsx
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.

Example · jsx
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.

Example · jsx
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

  • Be the first to comment on this lesson.