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.
DataGridPreview
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>
| Prop | Type | Default | Description |
|---|---|---|---|
| key | string | — | Column id / fallback data key. |
| header | ReactNode | — | Header cell content. |
| width / minWidth | number | 160 / 60 | Sizing in px. |
| sortable / resizable / filterable | boolean | — | Enable per-column features. |
| pinned | "left" | "right" | — | Freeze column during horizontal scroll. |
| editable | boolean | — | Allow inline editing when a row is in edit mode. |
| filterType | "text" | "select" | "text" | Filter input kind. |
| accessor | (row: T) => string | number | — | Custom value getter. |
| render | (row: T) => ReactNode | — | Custom cell renderer. |
| exportValue | (row: T) => string | number | — | Custom 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>
| Prop | Type | Default | Description |
|---|---|---|---|
| columns / data / getRowId | required | — | Column defs, row data, and a row key extractor. |
| rowHeight / height / overscan | number | 40 / 400 / 5 | Virtualization tuning. |
| selectable / selectedIds / onSelectionChange | mixed | — | Row selection, controllable. |
| sort / onSortChange | SortState | null | — | Controlled sort. |
| filters / onFilterChange | FilterState[] | — | Controlled filters (text input debounced 200ms). |
| serverSide | boolean | false | Treat data as pre-sorted/filtered/paginated by the caller. |
| loading | boolean | false | Shows a Spinner overlay without unmounting rows. |
| page / pageSize / onPageChange / totalRowCount | mixed | — | Enables a built-in Pagination footer. |
| onRowEdit | (rowId, values) => void | — | Enables inline editing; called on save. |
| enableExport | boolean | false | Shows a toolbar Export button that exports the current view to .xlsx. |
| groupBy / defaultGroupBy / onGroupByChange | string | undefined | — | Single-level grouping by a column key, set programmatically (no built-in drag-to-group UI yet). undefined = no grouping. |
| expandedGroups / defaultExpandedGroups / onExpandedGroupsChange | Set<string> | all expanded | Which group keys are expanded, controllable. |
| groupRowHeight | number | rowHeight | Height of a group header row. |
| onRowClick / onRowDoubleClick | (row: T, event) => void | — | Fires 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) => void | — | Fires on a data cell click, with the clicked column definition. |
DataGridHandle<T> (ref)
| Prop | Type | Default | Description |
|---|---|---|---|
| exportToExcel | (options?: { filename?, sheetName? }) => Promise<void> | — | Imperative export, e.g. for a custom trigger outside the built-in toolbar button. |