no-clone-element
Disallows 'cloneElement'.
Full Name in eslint-plugin-react-x
react-x/no-clone-elementFull Name in @eslint-react/eslint-plugin
@eslint-react/no-clone-elementPresets
x
recommended
recommended-typescript
recommended-type-checked
strict
strict-typescript
strict-type-checked
Rule Details
Using cloneElement is uncommon and can lead to fragile code. It also makes it harder to trace data flow. Try the alternatives instead.
Examples
Augmenting an element's props dynamically
Using cloneElement to inject props into a child element hides the data flow and breaks component encapsulation. Prefer passing props explicitly through render props or composition patterns.
// Problem: Using cloneElement to dynamically inject props into a child element
import { cloneElement } from "react";
const clonedElement = cloneElement(
<Row title="Cabbage">Hello</Row>,
{ isHighlighted: true },
"Goodbye",
);
console.log(clonedElement); // <Row title="Cabbage" isHighlighted={true}>Goodbye</Row>Wrapping children with injected props
Using cloneElement inside Children.map hides which props a child receives and breaks encapsulation. Prefer passing data explicitly via render props or by restructuring your component API.
// Problem: Using cloneElement to inject props into each child
import { Children, cloneElement, useState } from "react";
function List({ children }) {
const [selectedIndex, setSelectedIndex] = useState(0);
return (
<div className="List">
{Children.map(children, (child, index) =>
cloneElement(child, {
isHighlighted: index === selectedIndex,
}),
)}
<button onClick={() => setSelectedIndex((i) => (i + 1) % Children.count(children))}>
Next
</button>
</div>
);
}// Recommended: Pass isHighlighted explicitly via render props
import { useState } from "react";
function List({ items, renderItem }) {
const [selectedIndex, setSelectedIndex] = useState(0);
return (
<div className="List">
{items.map((item, index) => {
const isHighlighted = index === selectedIndex;
return renderItem(item, isHighlighted);
})}
<button onClick={() => setSelectedIndex((i) => (i + 1) % items.length)}>
Next
</button>
</div>
);
}
function App() {
return (
<List
items={products}
renderItem={(product, isHighlighted) => (
<Row key={product.id} title={product.title} isHighlighted={isHighlighted} />
)}
/>
);
}