These APIs allow you to create and work with React elements programmatically. Most of the time you’ll use JSX instead, but these functions are useful when working with element trees dynamically.
createElement()
Create and return a new React element of the given type.
function createElement(
type: string | ComponentType,
props?: object | null,
...children: ReactNode[]
): ReactElement
type
string | ComponentType
required
The type of element to create:
- A string for HTML elements (
'div', 'span', etc.)
- A React component (function or class)
- A React fragment (
React.Fragment)
- Or other special types (Suspense, StrictMode, etc.)
An object containing props to pass to the element. Can include:
- Any custom props
key - String or number to identify the element in lists
ref - Ref to access the underlying DOM node or component instance
- Special props like
className, style, event handlers, etc.
Pass null or omit if the element has no props.
Zero or more child elements. Can be:
- Other React elements
- Strings or numbers (rendered as text)
null, undefined, or false (rendered as nothing)
- Arrays of any of the above
Returns: A React element object.
Usage
Basic element creation:
import { createElement } from 'react';
// Equivalent to: <div>Hello</div>
const element = createElement('div', null, 'Hello');
// Equivalent to: <h1 className="title">Welcome</h1>
const heading = createElement('h1', { className: 'title' }, 'Welcome');
Multiple children:
// Equivalent to: <div><h1>Title</h1><p>Content</p></div>
const container = createElement(
'div',
null,
createElement('h1', null, 'Title'),
createElement('p', null, 'Content')
);
Component creation:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}
// Equivalent to: <Greeting name="World" />
const greeting = createElement(Greeting, { name: 'World' });
With key and ref:
import { createRef } from 'react';
const ref = createRef();
const element = createElement(
'input',
{
key: 'input-1',
ref: ref,
type: 'text',
placeholder: 'Enter text'
}
);
Dynamic element creation:
function renderList(items) {
return createElement(
'ul',
null,
items.map((item, index) =>
createElement('li', { key: index }, item)
)
);
}
Default Props
If the component has defaultProps defined, createElement will merge them with the provided props:
function Button({ color, text }) {
return <button style={{ color }}>{text}</button>;
}
Button.defaultProps = {
color: 'blue',
text: 'Click me'
};
// Uses default color='blue'
const button1 = createElement(Button, { text: 'Submit' });
// Overrides default with color='red'
const button2 = createElement(Button, { color: 'red', text: 'Delete' });
Special Props
These props have special meaning to React:
key - Used to identify elements in lists (not accessible via props.key)
ref - Used to access DOM nodes or component instances (treated specially in React 19+)
__self and __source - Used internally by React DevTools (should not be used in application code)
JSX is transformed to createElement calls by the compiler:
// JSX
<div className="container">
<h1>Hello</h1>
<p>World</p>
</div>
// Compiled to (classic runtime)
React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello'),
React.createElement('p', null, 'World')
);
React 17+ uses a new JSX transform that doesn’t require React.createElement. The above transformation only applies to the classic JSX runtime.
cloneElement()
Clone and return a new React element using an existing element as the starting point.
function cloneElement(
element: ReactElement,
props?: object | null,
...children: ReactNode[]
): ReactElement
The React element to clone. Must be a valid React element, not null or undefined.
Props to merge with the original element’s props. Props from this object will override props from the original element.
key and ref can be overridden
- If
ref is provided, the owner will be updated
undefined ref values are ignored (original ref is preserved)
Zero or more children to replace the original element’s children. If provided, these completely replace the original children.
Returns: A new React element with merged props and replaced children (if provided).
Throws: Error if the element argument is null or undefined.
Usage
Basic cloning:
import { cloneElement } from 'react';
const original = <button className="btn">Click me</button>;
// Add additional props
const cloned = cloneElement(original, { disabled: true });
// Result: <button className="btn" disabled>Click me</button>
Overriding props:
const original = <input type="text" defaultValue="Hello" />;
// Override defaultValue
const cloned = cloneElement(original, { defaultValue: "World" });
// Result: <input type="text" defaultValue="World" />
Replacing children:
const original = <div><p>Old content</p></div>;
// Replace children
const cloned = cloneElement(original, null, <p>New content</p>);
// Result: <div><p>New content</p></div>
Adding props to children:
function AddPropsToChildren({ children, color }) {
return (
<>
{React.Children.map(children, child =>
cloneElement(child, { style: { color } })
)}
</>
);
}
// Usage:
<AddPropsToChildren color="red">
<div>This will be red</div>
<span>This too</span>
</AddPropsToChildren>
Preserving keys:
// Original element with key
const original = <li key="item-1">Item</li>;
// Clone preserves key unless explicitly overridden
const cloned = cloneElement(original, { className: "active" });
// Result: <li key="item-1" className="active">Item</li>
Handling refs:
import { createRef, cloneElement } from 'react';
const ref1 = createRef();
const ref2 = createRef();
const original = <input ref={ref1} />;
// Cloning with new ref updates the owner
const cloned = cloneElement(original, { ref: ref2 });
// Now cloned element uses ref2 instead of ref1
When to Use cloneElement
Use cloneElement when:
- You need to inject props into children passed as
props.children
- You’re building higher-order components or component wrappers
- You need to modify or enhance existing elements
Prefer alternatives when:
- You can pass props directly to components (more explicit)
- You can use render props or context (more maintainable)
- You’re just creating new elements (use
createElement or JSX)
cloneElement is somewhat rare in modern React code. Consider using render props, context, or composition patterns instead when possible, as they’re often more maintainable.
Example: Enhancing Children
function TabPanel({ active, children }) {
return (
<>
{React.Children.map(children, (child, index) => {
return cloneElement(child, {
active: index === active,
key: index
});
})}
</>
);
}
function Tab({ active, children }) {
return (
<div className={active ? 'tab-active' : 'tab'}>
{children}
</div>
);
}
// Usage
<TabPanel active={0}>
<Tab>First Tab</Tab>
<Tab>Second Tab</Tab>
<Tab>Third Tab</Tab>
</TabPanel>
isValidElement()
Verify whether an object is a React element.
function isValidElement(object: any): boolean
Any JavaScript value to test.
Returns: true if the object is a valid React element, false otherwise.
Usage
Basic validation:
import { isValidElement } from 'react';
console.log(isValidElement(<div />)); // true
console.log(isValidElement(createElement('div'))); // true
console.log(isValidElement('hello')); // false
console.log(isValidElement(123)); // false
console.log(isValidElement(null)); // false
console.log(isValidElement({ type: 'div' })); // false (plain object)
Type checking in functions:
function renderItem(item) {
if (isValidElement(item)) {
return item;
}
return <div>{item}</div>;
}
renderItem(<span>Hello</span>); // Returns the element as-is
renderItem('Hello'); // Wraps in <div>
Filtering elements:
function extractElements(items) {
return items.filter(isValidElement);
}
const mixed = [
<div>Element 1</div>,
'just text',
<span>Element 2</span>,
42,
null
];
const elements = extractElements(mixed);
// Result: [<div>Element 1</div>, <span>Element 2</span>]
Conditional rendering helper:
function Wrapper({ children, fallback }) {
if (!children || !isValidElement(children)) {
return fallback;
}
return <div className="wrapper">{children}</div>;
}
// Usage
<Wrapper fallback={<div>No content</div>}>
<p>This is valid content</p>
</Wrapper>
What Makes a Valid Element
A valid React element is an object with:
{
$$typeof: Symbol.for('react.transitional.element'),
type: ..., // Component or tag name
props: ..., // Props object
key: ..., // Key (if provided)
// ... other internal properties
}
These objects are created by:
- JSX syntax:
<div />
createElement(): createElement('div')
cloneElement(): cloneElement(element)
Common Use Cases
Validating props.children:
function SingleChild({ children }) {
if (!isValidElement(children)) {
throw new Error('SingleChild requires a single React element as child');
}
return children;
}
Building flexible APIs:
function Icon({ icon }) {
// Accept either an element or a string
if (isValidElement(icon)) {
return icon;
}
return <i className={`icon-${icon}`} />;
}
// Both work:
<Icon icon="star" />
<Icon icon={<CustomStar />} />
Safe element manipulation:
function enhanceChild(child) {
if (!isValidElement(child)) {
return child; // Return non-elements as-is
}
return cloneElement(child, {
className: 'enhanced'
});
}
isValidElement only checks if something is a React element. It doesn’t validate if the element type is correct, if props are valid, or if the element will render successfully.