Component reference
DataGrid
A richer data surface with ownership modes, grouping and configurable columns.
Preview
Live previewOptional six-digit hex. Clear to restore the preset. Check contrast with your brand color.
Changes apply to this preview only.
Loading the interactive example?
Width adapts to the available space
"use client";
import { DataGrid } from "@pimolu/react";
export function DataGridExample() {
const rows = [
{ id: "1", name: "Maya Chen", team: "Design" },
{
id: "2",
name: "Noah Dubois",
team: "Engineering"
},
{
id: "3",
name: "Alice Martin",
team: "Design"
},
{
id: "4",
name: "Sofia Rossi",
team: "Research"
}
];
return (
<DataGrid
mode="client"
data={rows}
columns={[
{
id: "name",
header: "Name",
label: "Member name",
sortable: true,
resizable: true,
width: 220
},
{
id: "team",
header: "Team",
sortable: true,
resizable: true,
width: 160
}
]}
getRowId={(row) => row.id}
getRowLabel={(row) => `Select ${row.name}`}
caption="Workspace members"
selectable
defaultPageSize={2}
pageSizeOptions={[
2,
4
]}
/>
);
}More examples
Different configurations and compositions using the real Pimolu API. Each preview runs independently and follows the site appearance.
Server-driven order queue
The page plays the server: it filters, sorts and slices the rows itself, then feeds only the current page to the grid. The grid reports intent through onSortChange, onFilterChange, onPageChange and onPageSizeChange, and sizes pagination from totalRows. Selection is kept across pages because the parent owns selectedRowIds.
Grouping, resizing and column visibility
groupBy collects the filtered and sorted rows into expandable groups with their counts. The separators resize columns with the pointer and from the keyboard; columnWidths stays uncontrolled here while hiddenColumns is controlled by the page. The Columns menu keeps at least one column visible.
Empty result
When a manual request returns nothing, the grid still renders its headers and the empty state instead of collapsing.
Usage
Set mode=client when the grid owns local filtering, sorting and pagination. Server callbacks or totalRows infer server mode unless you specify a mode.
In server mode, provide the loaded page and totalRows, then handle intent through callbacks. Column definitions support resizing and visibility. Virtualized rows, pinned columns and spreadsheet editing are not APIs to assume here.
API reference
Generated from the public TypeScript declarations. Native HTML attributes are inherited where the component extends them; this reference includes Pimolu props and selected common native attributes.
PimoluDataGridSort
Type source| Name | Type | Default | Description |
|---|---|---|---|
columnIdRequired | string | — | Id of the sorted column. |
directionRequired | PimoluDataGridSortDirection | — | Active direction. |
columnIdRequiredstringNo default extracted.
Id of the sorted column.
directionRequiredPimoluDataGridSortDirectionNo default extracted.
Active direction.
PimoluDataGridColumn
Type source| Name | Type | Default | Description |
|---|---|---|---|
idRequired | string | — | Stable column id, also used as the fallback row property key. |
headerRequired | ReactNode | — | Visible header content. |
label | string | undefined | the text of `header`, then `id` | Plain-text name used by the sort button, the resize handle and the column-visibility menu. Defaults to the text of `header`, then `id`. |
accessor | ((row: T) => ReactNode) | undefined | — | Renders the cell content. |
cell | ((row: T) => ReactNode) | undefined | — | Renders the cell content; takes precedence over `accessor`. |
sortable | boolean | undefined | — | Enables the sort button and `aria-sort` on this column. |
align | PimoluDataGridAlign | undefined | "start" | Cell and header alignment. Defaults to "start". |
width | Property.Width<string | number> | undefined | — | Initial width. A number is interpreted as pixels and is the recommended form for resizable columns; a CSS string is also accepted. |
minWidth | number | undefined | 80 | Lower bound, in pixels, for keyboard and pointer resizing. Defaults to 80. |
maxWidth | number | undefined | 800 | Upper bound, in pixels, for keyboard and pointer resizing. Defaults to 800. |
resizable | boolean | undefined | — | Adds a draggable and keyboard-operable resize handle. |
hideable | boolean | undefined | — | When false, the column cannot be hidden from the column-visibility menu. An id explicitly listed in `hiddenColumns` is still hidden. |
searchValue | ((row: T) => string | number | null | undefined) | undefined | — | Raw value used by the global filter. |
sortValue | ((row: T) => string | number | null | undefined) | undefined | — | Raw value used for sorting. |
groupValue | ((row: T) => string) | undefined | the raw `row[id]` value, then the rendered cell text | Group label used with `groupBy`. Defaults to the raw `row[id]` value, then the rendered cell text. |
idRequiredstringNo default extracted.
Stable column id, also used as the fallback row property key.
headerRequiredReactNodeNo default extracted.
Visible header content.
labelstring | undefinedDefault: the text of `header`, then `id`
Plain-text name used by the sort button, the resize handle and the column-visibility menu. Defaults to the text of `header`, then `id`.
accessor((row: T) => ReactNode) | undefinedNo default extracted.
Renders the cell content.
cell((row: T) => ReactNode) | undefinedNo default extracted.
Renders the cell content; takes precedence over `accessor`.
sortableboolean | undefinedNo default extracted.
Enables the sort button and `aria-sort` on this column.
alignPimoluDataGridAlign | undefinedDefault: "start"
Cell and header alignment. Defaults to "start".
widthProperty.Width<string | number> | undefinedNo default extracted.
Initial width. A number is interpreted as pixels and is the recommended form for resizable columns; a CSS string is also accepted.
minWidthnumber | undefinedDefault: 80
Lower bound, in pixels, for keyboard and pointer resizing. Defaults to 80.
maxWidthnumber | undefinedDefault: 800
Upper bound, in pixels, for keyboard and pointer resizing. Defaults to 800.
resizableboolean | undefinedNo default extracted.
Adds a draggable and keyboard-operable resize handle.
hideableboolean | undefinedNo default extracted.
When false, the column cannot be hidden from the column-visibility menu. An id explicitly listed in `hiddenColumns` is still hidden.
searchValue((row: T) => string | number | null | undefined) | undefinedNo default extracted.
Raw value used by the global filter.
sortValue((row: T) => string | number | null | undefined) | undefinedNo default extracted.
Raw value used for sorting.
groupValue((row: T) => string) | undefinedDefault: the raw `row[id]` value, then the rendered cell text
Group label used with `groupBy`. Defaults to the raw `row[id]` value, then the rendered cell text.
PimoluDataGridLabels
Type source| Name | Type | Default | Description |
|---|---|---|---|
filterRequired | string | — | Accessible label of the filter input. |
filterPlaceholderRequired | string | — | Placeholder of the filter input. |
columnsRequired | string | — | Visible label of the column-visibility trigger. |
columnVisibilityRequired | string | — | Accessible name of the column-visibility dialog. |
selectAllRequired | string | — | Accessible label of the header select-all checkbox. |
selectRowRequired | (rowId: string) => string | — | Accessible label of a row checkbox. |
emptyRequired | string | — | Shown when there is no row to display. |
noResultsRequired | (query: string) => string | — | Shown when the global filter matches nothing. |
loadingRequired | string | false | Announced while loading. |
clearSelectionRequired | string | — | Label of the clear-selection button. |
selectedCountRequired | (count: number) => string | — | Text of the selection bar. |
showingRequired | (first: number, last: number, total: number) => string | — | Footer range announcement. |
pageSizeRequired | string | — | Label of the rows-per-page control. |
expandGroupRequired | (label: string) => string | — | Accessible label of a collapsed group header. |
collapseGroupRequired | (label: string) => string | — | Accessible label of an expanded group header. |
groupCountRequired | (count: number) => string | — | Row count shown in a group header. |
resizeColumnRequired | (label: string) => string | — | Accessible label of a resize handle. |
emptyGroupRequired | string | — | Group label used when the grouped value is empty. |
filterRequiredstringNo default extracted.
Accessible label of the filter input.
filterPlaceholderRequiredstringNo default extracted.
Placeholder of the filter input.
columnsRequiredstringNo default extracted.
Visible label of the column-visibility trigger.
columnVisibilityRequiredstringNo default extracted.
Accessible name of the column-visibility dialog.
selectAllRequiredstringNo default extracted.
Accessible label of the header select-all checkbox.
selectRowRequired(rowId: string) => stringNo default extracted.
Accessible label of a row checkbox.
emptyRequiredstringNo default extracted.
Shown when there is no row to display.
noResultsRequired(query: string) => stringNo default extracted.
Shown when the global filter matches nothing.
loadingRequiredstringDefault: false
Announced while loading.
clearSelectionRequiredstringNo default extracted.
Label of the clear-selection button.
selectedCountRequired(count: number) => stringNo default extracted.
Text of the selection bar.
showingRequired(first: number, last: number, total: number) => stringNo default extracted.
Footer range announcement.
pageSizeRequiredstringNo default extracted.
Label of the rows-per-page control.
expandGroupRequired(label: string) => stringNo default extracted.
Accessible label of a collapsed group header.
collapseGroupRequired(label: string) => stringNo default extracted.
Accessible label of an expanded group header.
groupCountRequired(count: number) => stringNo default extracted.
Row count shown in a group header.
resizeColumnRequired(label: string) => stringNo default extracted.
Accessible label of a resize handle.
emptyGroupRequiredstringNo default extracted.
Group label used when the grouped value is empty.
PimoluDataGridProps
Type source| Name | Type | Default | Description |
|---|---|---|---|
dataRequired | readonly T[] | — | Rows to display. Never mutated. |
columnsRequired | readonly PimoluDataGridColumn<T>[] | — | Column definitions. |
getRowIdRequired | (row: T) => string | — | Stable identity for a row, used by selection and React keys. |
getRowLabel | ((row: T) => string) | undefined | the localised "Select row <id>" label | Full accessible label of a row checkbox. Defaults to the localised "Select row <id>" label. |
caption | ReactNode | — | Visible table caption, also used as the accessible name. |
ariaLabel | string | undefined | — | Accessible name when no caption is rendered. |
mode | PimoluDataGridMode | undefined | — | Explicit ownership mode. Omit to infer it from the callbacks and `totalRows`. See `PimoluDataGridMode`. |
filterable | boolean | undefined | true | Shows the global filter input. Defaults to true. In client mode, matching is case-insensitive across `searchValue`, the rendered cell text and the primitive `row[column.id]` value. |
filter | string | undefined | — | Controlled filter value. |
defaultFilter | string | undefined | "" | Initial filter value when uncontrolled. |
onFilterChange | ((value: string) => void) | undefined | — | Called with the next filter value. |
sort | PimoluDataGridSort | null | undefined | — | Controlled sort. Pass `null` to clear. |
defaultSort | PimoluDataGridSort | null | undefined | null | Initial sort when uncontrolled. |
onSortChange | ((sort: PimoluDataGridSort | null) => void) | undefined | — | Called with the next sort; `null` when the sort is cleared. |
pagination | boolean | undefined | true | Shows the footer with the range, the page-size control and the pages. |
pageSize | number | undefined | — | Controlled rows per page. Omit to let `defaultPageSize` and the page-size control own it. |
defaultPageSize | number | undefined | 10 | Initial rows per page when uncontrolled. Defaults to 10. |
pageSizeOptions | readonly number[] | undefined | 10, 25, 50, 100 | Options offered by the page-size control. Defaults to 10, 25, 50, 100. |
onPageSizeChange | ((pageSize: number) => void) | undefined | — | Called when the page-size control changes. The internal page resets to 1. |
page | number | undefined | — | Controlled page, starting at 1. In server mode, size pagination from `totalRows`. |
defaultPage | number | undefined | 1 | Initial page when uncontrolled. Defaults to 1. |
onPageChange | ((page: number) => void) | undefined | — | Called with the next page. |
totalRows | number | undefined | `data.length` | Total number of rows on the server. Defaults to `data.length`. Setting it also infers `mode="server"`. |
selectable | boolean | undefined | false | Adds the selection column and the selection bar. The header checkbox selects the visible page only; selection persists across pages and filtering. |
selectedRowIds | readonly string[] | undefined | — | Controlled selected row ids. |
defaultSelectedRowIds | readonly string[] | undefined | — | Initial selection when uncontrolled. |
onSelectionChange | ((selectedRowIds: string[]) => void) | undefined | — | Called with the next selection, ordered like `data`. Ids selected on another server page are kept at the end instead of being dropped when the loaded page changes. |
groupBy | string | null | undefined | — | Id of the column used to group the visible rows. Group headers show the number of matching rows and can be expanded or collapsed. Filtering and sorting run before grouping; pagination slices rows before grouping, so a group may span several pages. In server mode, counts describe the loaded page. `null` or `undefined` disables grouping. |
defaultCollapsedGroups | readonly string[] | undefined | — | Group keys collapsed on first render. |
hiddenColumns | readonly string[] | undefined | — | Controlled ids of hidden columns. |
defaultHiddenColumns | readonly string[] | undefined | — | Initial hidden columns when uncontrolled. |
onHiddenColumnsChange | ((hiddenColumns: string[]) => void) | undefined | — | Called with the next hidden column ids, in column order. |
columnWidths | Readonly<Record<string, number>> | undefined | — | Controlled pixel widths, keyed by column id. |
defaultColumnWidths | Readonly<Record<string, number>> | undefined | — | Initial pixel widths when uncontrolled. |
onColumnWidthsChange | ((columnWidths: Record<string, number>) => void) | undefined | — | Called with the full width map after a pointer or keyboard resize. |
stickyHeader | boolean | undefined | false | Keeps the header visible while the table body scrolls. |
density | PimoluTableDensity | undefined | "md" | Row density. Defaults to "md". |
loading | boolean | undefined | false | Dims the table and announces a busy state. |
labels | Partial<PimoluDataGridLabels> | undefined | — | Overrides individual chrome labels. |
emptyState | ReactNode | — | Replaces the default empty message. |
className | string | undefined | — | Additional class names on the root. |
rowClassName | ((row: T, index: number) => string | undefined) | undefined | — | Additional class names per data row. |
dataRequiredreadonly T[]No default extracted.
Rows to display. Never mutated.
columnsRequiredreadonly PimoluDataGridColumn<T>[]No default extracted.
Column definitions.
getRowIdRequired(row: T) => stringNo default extracted.
Stable identity for a row, used by selection and React keys.
getRowLabel((row: T) => string) | undefinedDefault: the localised "Select row <id>" label
Full accessible label of a row checkbox. Defaults to the localised "Select row <id>" label.
captionReactNodeNo default extracted.
Visible table caption, also used as the accessible name.
ariaLabelstring | undefinedNo default extracted.
Accessible name when no caption is rendered.
modePimoluDataGridMode | undefinedNo default extracted.
Explicit ownership mode. Omit to infer it from the callbacks and `totalRows`. See `PimoluDataGridMode`.
filterableboolean | undefinedDefault: true
Shows the global filter input. Defaults to true. In client mode, matching is case-insensitive across `searchValue`, the rendered cell text and the primitive `row[column.id]` value.
filterstring | undefinedNo default extracted.
Controlled filter value.
defaultFilterstring | undefinedDefault: ""
Initial filter value when uncontrolled.
onFilterChange((value: string) => void) | undefinedNo default extracted.
Called with the next filter value.
sortPimoluDataGridSort | null | undefinedNo default extracted.
Controlled sort. Pass `null` to clear.
defaultSortPimoluDataGridSort | null | undefinedDefault: null
Initial sort when uncontrolled.
onSortChange((sort: PimoluDataGridSort | null) => void) | undefinedNo default extracted.
Called with the next sort; `null` when the sort is cleared.
paginationboolean | undefinedDefault: true
Shows the footer with the range, the page-size control and the pages.
pageSizenumber | undefinedNo default extracted.
Controlled rows per page. Omit to let `defaultPageSize` and the page-size control own it.
defaultPageSizenumber | undefinedDefault: 10
Initial rows per page when uncontrolled. Defaults to 10.
pageSizeOptionsreadonly number[] | undefinedDefault: 10, 25, 50, 100
Options offered by the page-size control. Defaults to 10, 25, 50, 100.
onPageSizeChange((pageSize: number) => void) | undefinedNo default extracted.
Called when the page-size control changes. The internal page resets to 1.
pagenumber | undefinedNo default extracted.
Controlled page, starting at 1. In server mode, size pagination from `totalRows`.
defaultPagenumber | undefinedDefault: 1
Initial page when uncontrolled. Defaults to 1.
onPageChange((page: number) => void) | undefinedNo default extracted.
Called with the next page.
totalRowsnumber | undefinedDefault: `data.length`
Total number of rows on the server. Defaults to `data.length`. Setting it also infers `mode="server"`.
selectableboolean | undefinedDefault: false
Adds the selection column and the selection bar. The header checkbox selects the visible page only; selection persists across pages and filtering.
selectedRowIdsreadonly string[] | undefinedNo default extracted.
Controlled selected row ids.
defaultSelectedRowIdsreadonly string[] | undefinedNo default extracted.
Initial selection when uncontrolled.
onSelectionChange((selectedRowIds: string[]) => void) | undefinedNo default extracted.
Called with the next selection, ordered like `data`. Ids selected on another server page are kept at the end instead of being dropped when the loaded page changes.
groupBystring | null | undefinedNo default extracted.
Id of the column used to group the visible rows. Group headers show the number of matching rows and can be expanded or collapsed. Filtering and sorting run before grouping; pagination slices rows before grouping, so a group may span several pages. In server mode, counts describe the loaded page. `null` or `undefined` disables grouping.
defaultCollapsedGroupsreadonly string[] | undefinedNo default extracted.
Group keys collapsed on first render.
hiddenColumnsreadonly string[] | undefinedNo default extracted.
Controlled ids of hidden columns.
defaultHiddenColumnsreadonly string[] | undefinedNo default extracted.
Initial hidden columns when uncontrolled.
onHiddenColumnsChange((hiddenColumns: string[]) => void) | undefinedNo default extracted.
Called with the next hidden column ids, in column order.
columnWidthsReadonly<Record<string, number>> | undefinedNo default extracted.
Controlled pixel widths, keyed by column id.
defaultColumnWidthsReadonly<Record<string, number>> | undefinedNo default extracted.
Initial pixel widths when uncontrolled.
onColumnWidthsChange((columnWidths: Record<string, number>) => void) | undefinedNo default extracted.
Called with the full width map after a pointer or keyboard resize.
stickyHeaderboolean | undefinedDefault: false
Keeps the header visible while the table body scrolls.
densityPimoluTableDensity | undefinedDefault: "md"
Row density. Defaults to "md".
loadingboolean | undefinedDefault: false
Dims the table and announces a busy state.
labelsPartial<PimoluDataGridLabels> | undefinedNo default extracted.
Overrides individual chrome labels.
emptyStateReactNodeNo default extracted.
Replaces the default empty message.
classNamestring | undefinedNo default extracted.
Additional class names on the root.
rowClassName((row: T, index: number) => string | undefined) | undefinedNo default extracted.
Additional class names per data row.
Accessibility
- Name the table and selected rows, and give each configurable column a plain-text label.
- Check resize handles with the keyboard and test grouping, selection and page changes with assistive technology. Deeper audits remain necessary for this complex family.