Row Drag and Drop
Grid supports drag and drop for reordering rows and transferring rows between grids.
<div controller={PageController} class="flex gap-4">
<div class="flex-1">
<h3 class="text-sm font-semibold mb-2">Team A</h3>
<Grid
records={m.left}
style="width: 100%"
border
columns={[
{
header: "",
align: "center",
pad: false,
items: (
<DragHandle class="cursor-move text-gray-400 hover:text-gray-600 px-1">
⋮⋮
</DragHandle>
),
},
{ header: "Name", field: "fullName" },
{ header: "City", field: "city" },
]}
dragSource={{ data: { type: "person", source: "left" } }}
onDropTest={(e) => e.source?.data?.type === "person"}
onDrop={(e, instance) =>
instance.getControllerByType(PageController).onDrop(e, "left")
}
/>
</div>
<div class="flex-1">
<h3 class="text-sm font-semibold mb-2">Team B</h3>
<Grid
records={m.right}
style="width: 100%"
border
columns={[
{ header: "Name", field: "fullName" },
{ header: "City", field: "city" },
]}
row={{ style: { cursor: "move" } }}
dragSource={{ data: { type: "person", source: "right" } }}
dropZone={{ mode: "insertion" }}
onDropTest={(e) => e.source?.data?.type === "person"}
onDrop={(e, instance) =>
instance.getControllerByType(PageController).onDrop(e, "right")
}
/>
</div>
</div> Team A
| Name | City | |
|---|---|---|
⋮⋮ | Alice Johnson | New York |
⋮⋮ | Bob Smith | Los Angeles |
⋮⋮ | Carol White | Chicago |
Team B
| Name | City |
|---|---|
| David Brown | Houston |
| Eva Green | Phoenix |
Drag rows to reorder within a grid or transfer between grids. Use the drag handle to initiate dragging.
Drag Handle
Use DragHandle to create a specific grab area instead of making the entire row draggable:
import { DragHandle } from "cx/widgets";
columns={[
{
header: "",
items: (
<DragHandle class="cursor-move text-gray-400 hover:text-gray-600 px-1">
⋮⋮
</DragHandle>
),
},
// ... other columns
]}
This provides better control and prevents accidental drags when clicking on other parts of the row.
Insertion Mode
Use dropZone={{ mode: "insertion" }} to show insertion indicators between rows:
<Grid
dragSource={{ data: { type: "record" } }}
dropZone={{ mode: "insertion" }}
onDropTest={(e) => /* validate drop */}
onDrop={(e) => /* handle drop */}
/>
Enabling Row Drag
Configure dragSource to make rows draggable:
<Grid
records={m.records}
dragSource={{ data: { type: "record" } }}
row={{ style: { cursor: "move" } }}
/>
Handling Drops
Implement onDropTest to validate drops and onDrop to handle the reordering:
<Grid
onDropTest={(e) => e.source?.data?.type === "record"}
onDrop={(e, { controller }) => controller.onDrop(e)}
/>
The onDrop handler receives information about the source records and target position:
onDrop(e) {
const draggedRecords = e.source.records.map((r) => r.data);
const insertionIndex = e.target.insertionIndex;
// Remove and reinsert records at new position
this.store.update(m.records, (records) => {
// ... reordering logic
});
}
Drag Source Configuration
| Property | Type | Description |
|---|---|---|
data | object | Custom data attached to the drag operation. |
mode | string | Drag mode: "move" (default) or "copy". |
Drop Event Properties
| Property | Description |
|---|---|
e.source.records | Array of dragged record objects with data and index. |
e.source.data | Custom data from dragSource. |
e.target.insertionIndex | Index where items should be inserted. |
Transferring Between Grids
Include a source identifier in the drag data to track which grid the row came from:
dragSource={{ data: { type: "person", source: "left" } }}
In the drop handler, use the source to remove from the correct grid:
onDrop(e, targetPath) {
const sourcePath = e.source.data.source;
// Remove from source grid
this.store.update(sourcePath, (records) =>
records.filter((r) => !draggedRecords.includes(r))
);
// Insert into target grid
this.store.update(targetPath, (records) =>
insertElement(records, insertionIndex, ...draggedRecords)
);
}
Configuration
| Property | Type | Description |
|---|---|---|
dragSource | object | Configuration for row dragging. |
dropZone | object | Drop zone configuration. Use mode: "insertion" for visual indicators. |
onDropTest | function | Test if a drop is valid. Return true to allow. |
onDrop | function | Handle the drop operation. |
Drop Zone Modes
| Mode | Description |
|---|---|
preview | Default mode. Shows a preview of the drop position. |
insertion | Shows insertion lines between rows for reordering. |
See also: Grid, Tree Drag and Drop, DragHandle