Row selection

Letting the user select whole rows with selectable.rows.

Last updated August 24, 2026

selectable.rows takes a SelectionMode — false, "single", or "multiple" — off by default, since selection claims the click a display-only grid shouldn't. Give getRowId alongside it for data that sorts, filters, or pages; without one a row is identified by its position, so a re-sort leaves the same positions selected under different rows.

Multi-select rows#

selectable={{ rows: "multiple" }}

Live example

This example runs as a real project on StackBlitz.

Open in StackBlitz
<DataGridComponent
  columns={columns}
  dataSource={rows}
  getRowId={(row) => String(row.Id)}
  selectable={{ rows: "multiple" }}
  onRowSelectionChange={({ selected }) => persist(selected)}
/>;

Props#

PropTypeDefaultDescription
selectable.rowsfalse | "single" | "multiple"falseHow many rows the user may select at once.
getRowId(row: Row, index: number) => stringrow positionA row's stable identity. Give one for data that sorts, filters, or pages, or a selection follows the position rather than the row.
defaultRowSelectionSelectionStateRow ids selected to start with, keyed as getRowId resolves them. Uncontrolled.
onRowSelect / onRowsSelect(event) => voidOnce per row newly selected, and once per interaction with every row it selected.
onRowDeselect / onRowsDeselect(event) => voidThe deselecting counterpart of each, above.
onRowSelectionChange(event: RowSelectionChangeEvent) => voidOnce per change with what it added, what it removed, and everything selected after — the one to persist from.

Payload shape#

RowSelectionChangeEvent<Row> — the payload of onRowSelectionChange, and the one to persist from:

FieldTypeDescription
addedreadonly ResolvedRow<Row>[]Rows this interaction newly selected.
removedreadonly ResolvedRow<Row>[]Rows this interaction deselected.
selectedreadonly ResolvedRow<Row>[]Every selected row, not only what this interaction changed.
selectionSelectionStateThe same rows, as ids only — readonly string[].

See imperative handle for ResolvedRow<Row>'s own fields. onRowSelect/onRowsSelect/onRowDeselect/onRowsDeselect fire the row(s) they name, each as a ResolvedRow<Row>, alongside the selection at that point.

Reading selection outside the grid's own tree#

useSelectionState subscribes to row, column, and cell selection together through the grid's ref — one combined hook, not three, matching how the grid treats all three as one concern internally — for a "N rows selected" toolbar living elsewhere on the page:

import { useRef } from "react";
import {
  DataGridComponent,
  useSelectionState,
  type DataGridApi,
} from "@gridkitjs/react";

function Toolbar({ gridRef }: { gridRef: RefObject<DataGridApi<Row> | null> }) {
  const { rowSelection, clearSelection, selectAllRows } =
    useSelectionState(gridRef);

  return (
    <div className="my-toolbar">
      <span>{rowSelection.length} row(s) selected</span>
      <button onClick={selectAllRows}>Select all</button>
      <button onClick={clearSelection}>Clear</button>
    </div>
  );
}
FieldTypeDescription
rowSelectionSelectionStateSelected row ids.
columnSelectionSelectionStateSelected column ids — see column selection.
cellSelectionCellSelectionStateThe selected cell, if any — see cell selection.
clearSelection() => voidClears row, column, and cell selection together.
selectAllRows() => voidSelects every row.

Before the grid mounts, the row/column fields read as empty arrays and the cell field reads null. See imperative handle for subscribe, the primitive this hook is built on.

Edit this page on GitHub