Chapter 78: cloneElement
Core Idea
cloneElement(element, props?, children?) creates a copy of an existing React element with some props overridden or added — a legacy escape hatch the docs steer away from, in favor of explicit render props or composition via children/named element props.
Key Concepts
- Signature:
cloneElement(element, newProps, newChildren?) — returns a new element with element's original props shallow-merged with newProps (new values override existing ones), optionally replacing children too.
- Historical use case: letting a parent inject extra props into a child element it didn't create (received as
children or another prop) — e.g. a Tabs component cloning each tab child to inject an isSelected prop, without the caller needing to pass it manually.
- Why the docs discourage it: cloning makes data flow implicit and fragile — the child element's actual rendered props depend on both what the original caller wrote and an invisible parent-side mutation, making the component harder to reason about and type. It also doesn't work with function components that don't forward arbitrary extra props predictably.
- Preferred alternatives: render props (passing a function as a prop that the parent calls with the data the child needs), or explicit composition (accepting specific named props/children slots) — both keep the actual data flow visible in the calling code rather than hidden inside a clone.
Code Examples
// Legacy pattern (discouraged):
const clonedChild = cloneElement(child, { isSelected: true });
// Preferred: explicit prop passed directly by the composing code
<Tab isSelected={index === activeIndex}>{child}</Tab>
- What it demonstrates: the difference between implicitly injecting a prop via cloning vs. explicitly passing it where the composition actually happens.
Key Takeaways
- Treat
cloneElement as a legacy pattern — reach for render props or explicit prop-passing/composition in new code.
- Cloning makes a component's actual runtime props partly invisible at the call site, which complicates debugging and TypeScript inference.
- It still exists and works for maintaining older codebases, but isn't the docs' recommended pattern for new component APIs.
Connects To
- Ch 15 (Passing Props to a Component): the explicit-prop-passing pattern favored as the alternative.
- Ch 77 (Children): another
children-manipulation utility with a similar "consider the explicit alternative first" framing.