Skip to content

Unmanaged Row Dragging

Enterprise

Unmanaged row dragging gives you the drag interaction without the automatic reorder. RowDragManager still owns the pointer gesture and paints the drop indicator, but on drop it leaves your data untouched — it just tells you what the user did and steps back. You decide what happens: apply the move, reject it, route the row somewhere else, or fold it into your own model.

That’s the distinction from Managed Row Dragging, where the grid reorders its own data so the change sticks with no code from you. Managed is the fast path; unmanaged is the control path — reach for it when the reorder has rules, lives server-side, or has to land somewhere other than the grid’s own array.

Opt in with { managed: false } and subscribe with onDrag:

import { RowDragManager } from '@zengrid/enterprise/grid';
const drag = new RowDragManager({ managed: false }); // unmanaged
const grid = new Zengrid(mount, { columns, /* … */ });
grid.setData(rows);
drag.attach(grid);
drag.onDrag((event) => {
// Fires on every phase — nothing moves until you make it move.
if (event.phase === 'drop' && event.plan) {
applyMyReorder(event.plan.fromSource, event.plan.toSource);
}
});

onDrag(fn) fires on every phase of the gesture, so you can preview, log, or gate the move as it happens. It returns an unsubscribe function.

Phase When plan
start The user picks a row up. null
move The pointer crosses rows during the drag. null
drop The row is released. the concrete reorder, or null for a no-op

Every event carries the same shape:

Field Meaning
phase 'start' · 'move' · 'drop'.
fromRow Display index the drag started on.
fromSource Source (dataset) index the drag started on.
overRow Display index under the pointer (-1 on start).
insertBeforeRow Display index the row would land before (-1 on start).
plan On drop, the source-index reorder { fromSource, toSource, toRow }, or null when the drop is a no-op. null on start/move.

The plan on a drop is the same decision managed mode would apply — so the simplest unmanaged handler reproduces managed behaviour by feeding it to moveRow yourself. moveRow is exported for exactly that:

import { RowDragManager, moveRow } from '@zengrid/enterprise/grid';
drag.onDrag((e) => {
if (e.phase !== 'drop' || !e.plan) return;
const data = readRowsFromGrid(grid);
grid.setData(moveRow(data, e.plan.fromSource, e.plan.toSource));
grid.refresh();
});
Managed (managed: true, default) Unmanaged (managed: false)
Drop reorders the grid’s data Yes, automatically No — you do it
Notifies via onChange (after commit) onDrag (every phase)
Best for plain reordering of the grid’s own array rules, vetoes, server-side order, external targets

Everything else is shared: handle still reserves dragging for a rowDragColumn() grip, the drop indicator still renders (import @zengrid/enterprise/styles.css), and detach() still tears it all down. Unmanaged dragging works against the natural (unsorted) row order, so use it on a grid without an active sort.

Drag a row in each tab. The first leaves the data alone (watch the console); the second hands the reorder to you; the third layers a rule on top — the top row is locked and nothing may drop above it.

managed: false — the drop indicator tracks the pointer but the grid never reorders itself. Open the console to watch start/move/drop fire; the rows snap back because nothing is wired to move them.