Vesture

Data

DataGrid

A virtualized, sortable, filterable, resizable data table — the most involved component in the library, and the one built for real production datasets rather than demo lists.

DataGrid

Preview

Email
Status
Salary
Actions
Role: Design2 rowsSalary: 192000
Jane Doe
jane@example.com
Design
Active
$98,000
Diego Cruz
diego@example.com
Design
Active
$94,000
Role: Engineering2 rowsSalary: 220000
Alex Kim
alex@example.com
Engineering
Active
$112,000
Priya Nair
priya@example.com
Engineering
On leave
$108,000
Role: Product2 rowsSalary: 221000
Sam Patel
sam@example.com
Product
Active
$105,000
Mei Chen
mei@example.com
Product
Active
$116,000

Usage

tsx
import { useRef } from "react";
import { DataGrid, type DataGridHandle } from "@vesture/react";

const gridRef = useRef<DataGridHandle<User>>(null);

<DataGrid
  ref={gridRef}
  columns={[
    { key: "name", header: "Name", sortable: true, editable: true },
    { key: "email", header: "Email", filterable: true },
    { key: "salary", header: "Salary", aggregate: "sum" },
  ]}
  data={users}
  getRowId={(u) => u.id}
  selectable
  enableExport
  groupBy="department"
  onRowEdit={(id, values) => saveUser(id, values)}
  onRowDoubleClick={(row) => router.push("/users/" + row.id)}
/>

// Or trigger export imperatively from your own UI:
gridRef.current?.exportToExcel({ filename: "users.xlsx" });

Behavior

  • Row virtualization computed manually from scrollTop / rowHeight / overscan — no external virtualization dependency.
  • Column resize via Pointer Events on a role="separator" handle; columns can pin left or right and stay sticky during horizontal scroll.
  • Inline row editing: Enter saves, Escape cancels.
  • Controlled independently for sort, filters, and selectedIds — or hand serverSide off to your own API.
  • enableExport renders a toolbar Export button; exportToExcel is also exposed via a ref for a custom trigger. Export reads whatever's currently sorted/filtered on screen, not the raw data prop, and lazy-loads the xlsx library on first use so it never weighs down the base bundle.
  • onRowClick / onRowDoubleClick / onCellClick fire with the row's data (and column, for cell clicks) plus the native mouse event — useful for row navigation or a custom detail panel. Clicking the row-select checkbox or an inline-edit action button doesn't also trigger onRowClick; those stop propagation.
  • groupBy partitions rows into single-level groups (no nested multi-level grouping), rendered as collapsible group-header rows ahead of their data rows in the same virtualized flat list — group headers and data rows can have different heights (groupRowHeight vs rowHeight). Groups default to expanded; expandedGroups/onExpandedGroupsChange control which are open. Select-all only selects the currently visible (non-collapsed-group) rows. Any column with aggregate set ('sum' | 'avg' | 'count' | 'min' | 'max', or a custom (rows) => ReactNode) shows its computed value inline in that group's header row.

Props

DataGridColumn<T>

PropTypeDefaultDescription
keystringColumn id / fallback data key.
headerReactNodeHeader cell content.
width / minWidthnumber160 / 60Sizing in px.
sortable / resizable / filterablebooleanEnable per-column features.
pinned"left" | "right"Freeze column during horizontal scroll.
editablebooleanAllow inline editing when a row is in edit mode.
filterType"text" | "select""text"Filter input kind.
accessor(row: T) => string | numberCustom value getter.
render(row: T) => ReactNodeCustom cell renderer.
exportValue(row: T) => string | numberCustom value for Excel export; falls back to accessor, then the raw row value. Not derived from render, since that returns a ReactNode.
aggregate'sum' | 'avg' | 'count' | 'min' | 'max' | ((rows: T[]) => ReactNode)Computed per-group when the grid is grouped (see groupBy), shown in this column's slot within the group header row.

DataGrid<T>

PropTypeDefaultDescription
columns / data / getRowIdrequiredColumn defs, row data, and a row key extractor.
rowHeight / height / overscannumber40 / 400 / 5Virtualization tuning.
selectable / selectedIds / onSelectionChangemixedRow selection, controllable.
sort / onSortChangeSortState | nullControlled sort.
filters / onFilterChangeFilterState[]Controlled filters (text input debounced 200ms).
serverSidebooleanfalseTreat data as pre-sorted/filtered/paginated by the caller.
loadingbooleanfalseShows a Spinner overlay without unmounting rows.
page / pageSize / onPageChange / totalRowCountmixedEnables a built-in Pagination footer.
onRowEdit(rowId, values) => voidEnables inline editing; called on save.
enableExportbooleanfalseShows a toolbar Export button that exports the current view to .xlsx.
groupBy / defaultGroupBy / onGroupByChangestring | undefinedSingle-level grouping by a column key, set programmatically (no built-in drag-to-group UI yet). undefined = no grouping.
expandedGroups / defaultExpandedGroups / onExpandedGroupsChangeSet<string>all expandedWhich group keys are expanded, controllable.
groupRowHeightnumberrowHeightHeight of a group header row.
onRowClick / onRowDoubleClick(row: T, event) => voidFires on row click / double-click. Doesn't fire when the click originates from the select checkbox or an edit action button.
onCellClick(row: T, column: DataGridColumn<T>, event) => voidFires on a data cell click, with the clicked column definition.

DataGridHandle<T> (ref)

PropTypeDefaultDescription
exportToExcel(options?: { filename?, sheetName? }) => Promise<void>Imperative export, e.g. for a custom trigger outside the built-in toolbar button.