material-react-table icon indicating copy to clipboard operation
material-react-table copied to clipboard

Rows and Cells don't have a stable keys if the row is move to another index

Open Mathieu-COSYNS opened this issue 5 months ago • 1 comments

material-react-table version

3.2.1

react & react-dom versions

18.3.1

Describe the bug and the steps to reproduce it

Rows and Cells don't have a stable keys if the row is move to another index. This cause users to lose focus if the row order change.

  1. Render a table with some data with a cell that has a input field
  2. Focus on the input
  3. Reorder the table (programmatically)

Why this Matters

Preserves the input DOM node, keeping focus when rows get reordered.

Minimal, Reproducible Example - (Optional, but Recommended)

https://codesandbox.io/p/sandbox/awesome-chebyshev-lvrv4z

Screenshots or Videos (Optional)

Relevant lines of codes

https://github.com/KevinVandy/material-react-table/blob/8293b961523dc14878bf93af6122c6766e7c2233/packages/material-react-table/src/components/body/MRT_TableBodyRow.tsx#L251

https://github.com/KevinVandy/material-react-table/blob/8293b961523dc14878bf93af6122c6766e7c2233/packages/material-react-table/src/components/body/MRT_TableBody.tsx#L178

Do you intend to try to help solve this bug with your own PR?

Yes, I am also opening a PR that solves the problem along side this issue

Terms

  • [x] I understand that if my bug cannot be reliably reproduced in a debuggable environment, it will probably not be fixed and this issue may even be closed.

Mathieu-COSYNS avatar Aug 27 '25 14:08 Mathieu-COSYNS

In React, keys should represent the identity of the underlying data, not its position in the array. Currently, the row and cell keys include row.index / staticRowIndex. This causes React to treat a row as a different element whenever its order changes, even though it’s still the same underlying row.

That leads to issues like:

  • DOM nodes being torn down and recreated when rows are reordered.
  • Input fields losing focus (as shown in the demo).
  • Any stateful components inside the row/cell resetting unnecessarily.

By instead using only a stable row identifier (e.g., row.id, which can come from getRowId), React can correctly preserve the existing DOM nodes when rows move, keeping input focus and local state intact.

So it’s not just “removing info” from the key, but making sure the key reflects the row’s identity rather than its position.

This aligns with React’s own guidance:

Pitfall You might be tempted to use an item’s index in the array as its key. In fact, that’s what React will use if you don’t specify a key at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs. (https://react.dev/learn/rendering-lists#rules-of-keys)

I included a sandbox demo showing how the current implementation causes focus loss.

Mathieu-COSYNS avatar Oct 01 '25 08:10 Mathieu-COSYNS