Difference between createElement and cloneElement.
React.createElement(type, props, ...children) creates a brand-new element from scratch — JSX compiles to it. React.cloneElement(element, props, ...children) copies an EXISTING element, shallow-merging new props over its original ones. cloneElement is for injecting props into children you received.
Both produce React elements, but one creates from nothing and the other copies and tweaks an existing element.
React.createElement
React.createElement(type, props, ...children)Creates a new element from scratch. This is what JSX compiles to — <div className="x">hi</div> becomes React.createElement("div", { className: "x" }, "hi"). You almost never call it directly; you write JSX.
React.cloneElement
React.cloneElement(element, newProps, ...newChildren)Takes an existing element and returns a copy of it with:
- its original props preserved,
newPropsshallow-merged on top (new values win),keyandrefoverridable,- children replaced if you pass new ones.
When you actually use cloneElement
The real use case: you receive elements as props.children and need to inject extra props into them without the parent knowing. A classic pattern in compound components:
function RadioGroup({ value, onChange, children }) {
return React.Children.map(children, (child) =>
React.cloneElement(child, { // inject group state into each <Radio>
checked: child.props.value === value,
onChange,
})
);
}
// <RadioGroup><Radio value="a" /><Radio value="b" /></RadioGroup>Each <Radio> gets checked/onChange injected even though the consumer didn't pass them.
Key distinctions
createElement | cloneElement | |
|---|---|---|
| Input | a type (tag/component) | an existing element |
| Props | only what you pass | original props + merged overrides |
| Typical use | (via JSX) everywhere | injecting props into received children |
The caveat
cloneElement is somewhat of an escape hatch — it creates an implicit contract (the child must accept the props you inject). Modern React often prefers Context or render props over cloneElement for compound components, because they're more explicit. Know cloneElement, but mention the alternatives.
The framing
"createElement builds a new element from a type and props — it's what JSX compiles to, so you rarely call it directly. cloneElement copies an existing element, keeping its original props and shallow-merging new ones on top. The real use is injecting props into elements you received as children — like a RadioGroup passing checked/onChange into each Radio. It works, but it's an escape hatch with an implicit contract; for compound components, Context is often the cleaner modern choice."
Follow-up questions
- •What does JSX compile to?
- •Give a real use case for cloneElement.
- •How are props merged in cloneElement?
- •Why might Context be preferred over cloneElement for compound components?
Common mistakes
- •Thinking cloneElement deep-merges props — it's a shallow merge.
- •Not knowing JSX compiles to createElement.
- •Using cloneElement where passing props directly or using Context would be clearer.
- •Forgetting cloneElement preserves the original key/ref unless overridden.
Performance considerations
- •Both are cheap object creation. cloneElement over many children (React.Children.map) is fine at typical scale; the concern is architectural clarity, not performance.
Edge cases
- •Cloning an element whose child doesn't accept the injected prop.
- •Overriding key vs ref via cloneElement.
- •Cloning with new children vs preserving original children.
Real-world examples
- •Compound components (Tabs, RadioGroup, Menu) injecting shared state into children.
- •UI libraries cloning a trigger element to attach event handlers and ARIA props.