Rows

Row Reorder

Drag the grip, or move the focused row with Alt and the arrow keys. Reordering rewrites data, so it is meant for a grid the user is arranging rather than one a sort is already ordering.

Basic Usage

Drag the grip in the first column, or focus a row and press Alt with an arrow key. The readout is the live order of grid.data, and the log below it is what onReorder reports.

order: Hoang, Bruno, Bruno, Farid, Jonas, Quyen
__dg-row-handle__
Name
Team
Role
Hoang Kowalski
Design
Manager
Bruno Nguyen
Growth
Support
Bruno Dubois
Design
Manager
Farid Haddad
Growth
Analyst
Jonas Yilmaz
Core
Support
Quyen Tanaka
Growth
Analyst
6 rows
  • No moves yet.
import { createDataGrid, rowReorder } from '@sv5ui/datagrid';

const grid = createDataGrid<Task>({
  data: tasks,
  columns,
  getRowId,
  features: [
    rowReorder({
      // The grip column, pinned to the left edge. On by default.
      handle: true,

      // Rows that refuse to move themselves. Others can still land beside them.
      isRowDraggable: (task) => !task.locked,

      // After a move, with data already reordered.
      onReorder: ({ node, from, to, data }) => {
        console.log(node.id, from, '->', to);
        save(data.map((task, index) => ({ id: task.id, position: index })));
      }
    })
  ]
});

Rows That Stay Put

isRowDraggable decides per row. A row it refuses has a disabled grip and cannot be lifted, but the others can still be dropped either side of it.

__dg-row-handle__
Name
Status
Hoang Kowalski
invited
Bruno Nguyen
invited
Bruno Dubois
active
Farid Haddad
suspended
Jonas Yilmaz
active
Quyen Tanaka
suspended
6 rows
import { getRowReorder } from '@sv5ui/datagrid';

// Move a row to a rendered index
getRowReorder(grid)?.moveRow('3', 0);
grid.api.moveRow?.('3', 0);

// The drag in progress, for an indicator of your own
getRowReorder(grid)?.drag;   // { sourceId, targetIndex } | null

grid.events.on('rowMoved', ({ id, from, to }) => save(id, from, to));

Reorder and Sort Do Not Mix

This grid registers both, which the two grids above deliberately do not. Move the top row to the bottom while unsorted and the two lines agree. Sort by name, move it again, and the data line changes while the screen line does not: the move happened and the sort stage put the rows straight back.

unsorted

in the data: Hoang, Bruno, Bruno, Farid, Jonas, Quyen

on the screen: Hoang, Bruno, Bruno, Farid, Jonas, Quyen

__dg-row-handle__
Team
Role
Hoang Kowalski
Design
Manager
Bruno Nguyen
Growth
Support
Bruno Dubois
Design
Manager
Farid Haddad
Growth
Analyst
Jonas Yilmaz
Core
Support
Quyen Tanaka
Growth
Analyst
6 rows
// Reordering rewrites data, so an active sort re-sorts it immediately:
// the stored order changes and the screen does not. Clear the sort before
// offering the grip.
getSorting(grid)?.setSort([]);

// A grid meant for reordering is usually one without sortable columns at
// all, or one that turns the grip off while a sort is in force:
const canReorder = $derived((getSorting(grid)?.sort.length ?? 0) === 0);

rowReorder() Options

OptionDefault
handletrue
isRowDraggable() => true
onReorder-

Row Reorder State

What getRowReorder(grid) exposes. moveRow is also on grid.api.

MemberDescription
moveRow(id, index)Moves a row to a rendered index
dragThe drag in progress, for an indicator of your own
canDrag(node)The same question the grip asks before it lifts a row
nudge(id, delta)Moves a row one place, which is what the keyboard bindings call

Keyboard and Pointer

InputAction
Alt + Arrow upMoves the focused row one place up
Alt + Arrow downMoves it one place down
Drag the gripLifts a copy of the row that follows the cursor and auto-scrolls at the edges