Foundation component ยท Data editing

Data Grid

An editable grid for records, cell ranges, and keyboard-driven work.

Live playground

1Quantum ManufacturingBerlin, GermanyVeronica Han10quantum.com
2Synergy SolutionsCape Town, SAMin-ji Kim76synergy.com
3Apex NetworksZurich, SwitzerlandLars Jensen160apex.com
4Fusion VenturesCairo, EgyptLily Sinh Katty320fusion.com
5Vertex BioDublin, IrelandWei Chen810vertex.com
6Cortex AIBogotรก, ColombiaRachel Green1200cortex.com
7Pinnacle EnergyManila, PhilippinesSarah Jenkins6pinnacle.com
8Horizon FinanceChicago, USAMichael Chang85horizon.com
Double-click a cell to edit. Drag across cells to select a range.

When to use it

  • Use Data Grid when records are edited in place or users need to select a two-dimensional range.
  • Use Data Table for read-only comparison and summaries. Its native table structure needs less interaction machinery.
  • Show the shared Selection Toolbar for row selection, with batch actions supplied by the consumer. Keep cell-range selection separate from row actions.
  • The headless useDataGrid primitive owns selection, sorting, sizing, and atomic edit transactions. The styled component supplies Lenso cell geometry and interaction surfaces.
  • Use the same quiet header, row height, typography, and selection surface as Data Table. Cell boundaries are faint guides for editing and range selection; the active cell and edit boundary carry the strongest emphasis.

Editing and configuration

  • Double-click or press Enter to edit. Enter commits; Escape cancels. Drag to select a range, use arrow keys to move, or copy and paste tab-separated cells.
  • Set readOnly, showRowSelection, showRowNumbers, sortable, cellSelection, or resizable independently.
  • Each column can define parsing, validation, editable rules, rendering, and a cell-specific completion callback. Validation receives the final proposed rows, the original rows, the TanStack table, and optional external data, so linked rules can be checked before any change is applied.
  • Use tableOptions for TanStack Table options, tableColumn for per-column options, and tableRef to access the live API for the registered features. Grid-level callbacks remain convenient for cell commits, grouped row commits, selections, and sorting.

Implementation

Validation sees the candidate transaction. The ref exposes TanStack's full table instance.

import { useRef } from "react";
import { DataGrid, type DataGridColumn } from "@lenso/ui/data-grid";
import type { DataGridTable } from "@lenso/primitives/data-grid";

type Company = { id: string; name: string };
type Rules = { reservedNames: ReadonlySet<string> };
const tableRef = useRef<DataGridTable<Company>>(null);
const rules: Rules = { reservedNames: new Set(["lenso"]) };

const columns: DataGridColumn<Company, Rules>[] = [
  {
    id: "name",
    header: "Company",
    getValue: (row) => row.name,
    setValue: (row, value) => ({ ...row, name: String(value) }),
    tableColumn: { sortingFn: "alphanumeric" },
    validate: (value, row, { rows, data }) => {
      const name = String(value).trim();
      if (!name) return "Name is required";
      if (data?.reservedNames.has(name.toLowerCase())) return "Name is reserved";
      return rows.some((other) => other.id !== row.id && other.name === name)
        ? "Name already exists"
        : null;
    },
  },
];

<DataGrid
  label="Companies"
  rows={rows}
  columns={columns}
  getRowId={(row) => row.id}
  onRowsChange={setRows}
  validationData={rules}
  tableOptions={{ enableMultiCellRangeSelection: false }}
  tableRef={tableRef}
  onCellEditComplete={(change) => saveCell(change)}
  onRowEditComplete={(change) => auditRow(change)}
/>;
Lenso UI