New to KendoReactStart a free 30-day trial

Drag and Drop Rows between Grids with the Common Drag&Drop Hooks

Updated on Aug 31, 2026

Environment

Product Version16.0.0
ProductProgress® KendoReact Grid

Description

You want to drag and drop rows between two separate KendoReact Grid instances. The built-in rowReorderable prop only supports reordering within a single Grid because its internal drag engine validates that the drag source and drop target belong to the same Grid <tbody>—drops between two different Grids never fire.

This knowledge base article also answers the following questions:

  • How to implement cross-Grid drag and drop in KendoReact?
  • Why does rowReorderable not work when dragging a row to a different Grid?
  • How to use useDraggable and useDroppable with the Grid rows prop?
  • How to isolate a drag-and-drop context so it does not interfere with other Drag&Drop functionality on the page?
  • How to show a custom drag hint that follows the cursor across both Grids?

Solution

Implement a single custom row component using the useDraggable and useDroppable hooks from the @progress/kendo-react-common package, and attach it to both Grids through the rows.data option.

  1. Create an isolated React.createContext({}) instance and pass it as the context option to useDraggable, useDroppable, and the DragAndDrop component. This scopes the drag-and-drop state to these two Grids only, so it does not interfere with any other Drag&Drop functionality that might exist elsewhere on the page.
  2. Wrap both Grids in a single shared DragAndDrop component that uses the isolated context—this is required for the useDroppable hook to detect a valid drop.
  3. Define the custom row once, at module level, and reuse it for both Grids. Each row reads which Grid it belongs to from a small GridIdContext instead of receiving it through props, so the row component keeps a stable identity and is not recreated on every render.
  4. Spread the trProps object that the Grid passes to the custom row onto the <tr> element—it carries the attributes (role, aria-rowindex, click handlers, and so on) that the Grid relies on for its own behavior.
  5. Track the item and Grid currently being dragged in refs (not state) inside a TransferContext, so the drag callbacks always read the latest values without triggering extra renders while dragging.
  6. Render a single fixed-position element as the drag hint and pass its ref to useDraggable. The hint follows the pointer via onDrag and is shown only while a row is being dragged, giving the user a visual cue as they move a row from one Grid to the other.
  7. On drop, call a shared moveItem function that removes the item from its source Grid's data and adds it to the target Grid's data.

Remove rowReorderable from both Grids when combining this pattern with them—the two systems are independent, and combining them leads to conflicting drag event listeners.

The following example demonstrates dragging a row from one Grid and dropping it onto a row of the other Grid to move the corresponding data item between the two data sources.

Example
View Source
Loading ...

See Also

In this article
EnvironmentDescriptionSolutionSee Also
Not finding the help you need?
Contact Support