Try @eslint-react/kit@beta
logoESLint React

no-clone-element

Disallows 'cloneElement'.

Full Name in eslint-plugin-react-x

react-x/no-clone-element

Full Name in @eslint-react/eslint-plugin

@eslint-react/no-clone-element

Presets

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} />
      )}
    />
  );
}

Versions

Resources

Further Reading

On this page