Data Grid
A data grid driven by a TanStack Table v9 instance and rendered with react-aria's Table, which brings cell keyboard navigation, aria-sort, selection, column resizing, row drag and drop and virtualization.
Overview
Table
Create the table with useTable({ features: dataGridFeatures, ... }). The exported features cover sorting, filtering with facets, pagination, selection, row expanding (tree rows from getSubRows), row and column pinning, ordering, visibility and sizing, with client-side row models. For server-side data (or to show every row), set manualSorting/manualFiltering/manualPagination.
Column meta takes:
- `headerTitle`, `headerClassName` and `cellClassName`.
- `skeleton`: the cell shown in loading rows.
- `autoSize`: the column takes the remaining width (not measured from content).
- `headerColSpan`: the header spans the next visible columns on its pin side, e.g. "Quantity" over the amount and its unit. Covered headers take its accessible name and the last one keeps the resize handle.
Parts
Wrap them in DataGrid table={table} recordCount={…}:
- `DataGridTable` and `DataGridPagination`.
- `DataGridColumnHeader`: sort indicator, plus a menu for pinning, moving and visibility when
tableLayoutenables them. - `DataGridColumnVisibility`: a column visibility menu.
- `DataGridColumnFilter`: faceted; use
filterFn: "arrHas". - `DataGridRowSelect`: a row checkbox, with
enableRowSelection. - `DataGridRowPin`: pins to the top, or the bottom with
position="bottom". - `DataGridRowActions`: a row's actions as
DropdownMenuItems behind a menu button, named fromrowLabel. It doesn't triggeronRowClick, and with no items it shows a disabled "no actions" entry. - `DataGridRowDragHandle`: with
onRowsReorder. - `DataGridRowExpand`: shows
getSubRowschildren, indented by depth — or, withgetRowCanExpandandDataGridTable'srenderExpandedRow, a full-width details row. - `DataGridSelectionBar`: shows while rows are selected — the count (announced, with how many are on other pages), your bulk actions as children and "Clear selection".
Rows
- `onRowClick`: makes rows actionable (click or Enter).
- `onRowHover`: fires when the pointer enters a row, e.g. to prefetch its details.
- `isLoading`: shows skeleton rows (
meta.skeleton) or a spinner. - Footer:
DataGridTable'sfooterContenttakes footer rows (DataGridTableFootRowwithDataGridTableFootRowCell,colSpanto span columns);tableLayout.footerBackgroundtints them.
Infinite scroll
DataGridTable's onFetchMore fires near the end of the loaded rows (fetchMoreScrollOffset, in viewport heights), isFetchingMore shows a loading row and hasMore={false} stops it with allRowsLoadedMessage. Works with isVirtualized.
Layout and styling
- `tableLayout.columnsDraggable`: lets users drag headers to reorder columns; keyboard users use the header menu's move actions, and pinned columns stay put.
- `tableLayout`: also takes
rowRounded,headerBorderandcolumnsResizeMode("onEnd"commits the width on release and draws a line at the pointer while dragging). - `tableClassNames`: adds classes to parts of the table (
base,header,headerSticky,body,bodyRow,footer,edgeCell). - Surfaces: pinned cells and sticky headers paint
--data-grid-surface(else--cardinside aCard, else--background) and carrydata-pinned/data-last-col.
i18n
The i18n prop on DataGrid replaces every built-in string ({ labels: { sortAscending, rowsPerPage, paginationInfo: ({ from, to, count }) => …, goToPage: (page) => …, … } }, defaults in defaultDataGridI18n). Specific props like emptyMessage or the pagination labels still win.
Installation
- 1
Register the @fma-ds namespace in components.json (once)
- 2
Add the item
Files land in
components/fma-ds/data-grid.tsx; npm and registry dependencies are installed along with them.
Dependencies
- npm
- @tanstack/react-table@^9.3.1cn@^0.5.0lucide-react@^1.61.0react-aria-components@^1.22.1