API reference
DataGrid, DataGridProvider, ColumnDef, and the CellType contract.
This page is generated from the real TypeScript source at build time through AutoTypeTable. Every exported symbol also carries a JSDoc comment in source, reproduced in the tables below.
<DataGrid>
Prop
Type
This is a convenience wrapper: provider, scroll root, header, and body in one component. Compose
DataGridProvider, DataGridRoot, DataGridHeader, and DataGridBody directly instead when you
need a toolbar, overlays, or a context menu (see the Quick start).
Looking for every event/callback?
This page's prop tables are a curated subset. Events & state walks
through every event source (including onSelectionChange and onColumnLayoutChange) with
payload shapes and firing semantics. DataGridSyncProps in store/types.ts remains the full source of truth.
data vs defaultData
These are mutually exclusive (React value/defaultValue semantics). Passing both makes data
win, and dev mode warns once. See
Events & state: the three shapes for
what each shape means, and Quick start for a worked example.
Imperative handle
The ref prop receives the grid's DataGridApi: actions, store, scrollTo, focus,
startEditing, stopEditing, getSelection, setSelection, getRow, and getViewRowIds. The
object is stable for the grid's lifetime, so a toolbar or effect can hold it and call into the
grid without re-rendering when the grid changes:
const gridRef = useRef<DataGridApi<Order> | null>(null);
<DataGrid ref={gridRef} data={orders} columns={columns} getRowId={(o) => o.id} />
// from a toolbar button or an effect
gridRef.current?.scrollTo({ rowId: order.id, columnId: "symbol" });
gridRef.current?.actions.selectCell({ rowId: order.id, columnId: "symbol" });getSelection,getRow, andgetViewRowIdsare snapshots at call time. They never re-render the calling component.getViewRowIdsreturns one entry per view row, in view order, so entryiis always view rowi. An unloaded row of a lazy grid gives its placeholder id (__lazy-unloaded-<index>), the same iduseDataGridRowIdsreturns.setSelectionapplies a whole selection (a range, a range stack, row and column channels) in stableCellRefterms, or clears the selection withnull. It emits like a gesture:onSelectionChangefires when the result differs from the grid's current value. Selecting a single cell staysactions.selectCell(ref).startEditingopens an edit session at the named cell;stopEditingdiscards the draft without committing.startEditingdoes nothing on areadOnlygrid, on areadOnlycell, and on a cell whose type declaresactivate, like the keyboard edit gestures.focusscrolls the active cell into view and lands on it. With no active cell, it focuses the grid, whose onboarding seeds (0,0). It is a no-op while an edit session is open.- For manual composition (
DataGridProvider+DataGridRoot), pass thereftoDataGridProvider, or calluseDataGridApi(ref)in any component under the provider. A toolbar next toDataGridRootcan use the handle.scrollToandfocusdo nothing until aDataGridRootmounts.
<DataGridProvider>
This is the composable entry point. It has the same sync props as DataGrid above, including
cellTypes, labels, and duplicateRow:
Prop
Type
Doesn't take every DataGrid prop
rowHeight, density, className, emptyState, loading, loadingState,
getRowClassName, and getCellClassName live on DataGridRoot when composing
directly. DataGrid passes its own copies of these straight through to the DataGridRoot that
it renders. onFill is not a prop on either. It is an option to the useDataGridFill()
hook of the data-grid-fill add-on (see Fill handle), since fill itself
lives outside the core.
store: external store ownership
By default DataGridProvider creates and owns its store. When the store must live OUTSIDE the
provider's render (a panel beside the grid that reads it without a provider above, one store
shared by several provider trees) create it with useDataGridStoreProps(props) and feed it in
through the store prop (on both DataGridProvider and DataGrid):
const gridRef = useRef<DataGridApi<Order> | null>(null);
const { store } = useDataGridStoreProps({ data, columns, getRowId, onDataChange: handleDataChange });
function handleDataChange(next: readonly Order[], change: DataChange<Order>) {
setData(next);
saveOrders(change.ops).catch((error) => {
gridRef.current?.actions.setCellErrors(parseFieldErrors(error)); // the rejection lands after mount
});
}
return (
<>
<PageErrorPanel store={store} /> {/* beside the grid — no provider above it */}
<DataGrid ref={gridRef} store={store} />
</>
);useDataGridStorePropstakes the same sync props as the provider and keeps the store in sync with them on every render. Pass it the same live props the grid renders from.- With
storeset, the provider is a pure context shell: it creates nothing, syncs nothing, and subscribes to nothing. YouruseDataGridStorePropscall owns the store. - Imperative calls from your own component (a server follow-up in
onDataChange, a WebSocket push of validation errors) need no lifted store: by the time the async handler resolves the handle is set, sogridRef.current?.actions.…reaches the same actions. The liftedactionsis the only actions source on the first render, before the handle is set. store.getState()andstore.subscribe()are reachable from outside React for anything the selector hooks can't reach. The handle's read-onlystoreoffers the same pair once the grid is mounted.
plugins
readonly DataGridPlugin[], optional, on both DataGridProvider and DataGrid. Each entry is
an add-on (or your own code) that reaches into the grid through six optional members: an
Overlay component, a rowBands contribution, an onDataChange observer, commands, a
keymap, and a Mount component. Array order is precedence and visual order.
See Plugins for the full contract, and
Multiplayer presence, Fill handle, and
Undo & redo for three first-party consumers.
Identity is entry-wise
The grid compares the list entry-wise (same length, same name per entry, every member
identity-equal) so a fresh [plugin] array per render is harmless while the plugin keeps its
identity. A changed plugin member re-resolves the grid's plugins and remounts the plugin
components whose type changed. A plugin object attaches to one grid; the same object on two
grids dev-errors, and the second grid excludes it.
Hooks
State access is hooks only. Call them under DataGridProvider. The one way out is
useDataGridStoreProps (above). It hands you the store itself for code outside the
provider's subtree. The full list lives in store/hooks.ts. These are the ones you will reach
for most:
useDataGridActions(): the single stable actions object (setSorts,setFilters,setSearch,setColumnWidth,setColumnOrder,setColumnPin,setColumnHidden,setColumnLayout,setSelection,autosizeColumns,selectCell,extendTo,startEditing,commitCellEdit,deleteSelection,updateCells,updateRows,commitChange,reconcileView,setCellErrors,clearCellErrors, plus the row operationsinsertRow,duplicateRows,deleteRows. See Row operations). The complete list is theDataGridActionstype.commitChange(change)applies a wholeDataChangeoperation batch in one write and emitsonDataChangeonce, so it lands on the undo stack as a single entry; it is a no-op on areadOnlygrid and does not revalidate values.useDataGridViewStale(): true when a write left the sorted order stale: a deferredupdateCellsbatch, or an edit, paste, fill, or cleared selection that touched a column the active sort or filter reads. See Streaming updates.useDataGridCellTypes(): the resolved cell-type registry (built-ins or consumer-provided), for tooling that needs to inspect or resolve a column's renderer/editor.useDataGridActiveColumn(): the active cell's column index (ornull), for tooling that only cares about the active column.useDataGridActiveCell(),useDataGridSelection(),useDataGridGetSelectionValues(),useDataGridEditing()useDataGridSortState(),useDataGridFilterState(),useDataGridSearchText()useDataGridVisibleColumns(),useDataGridAllColumns(),useDataGridColumnWidth(id),useDataGridIsColumnHidden(id)useDataGridLabels(),useDataGridKeymap(),useDataGridReadOnly()useDataGridScrollToCell(): imperative scroll to aCellRef.useDataGridScrollToCellAt(): the same scroll to aViewCoord.useDataGridApi(ref?): the grid's imperative handle (DataGridApi); see Imperative handle.useDataGridCellErrors(): the full post-commit server-error map. See Editing & cell types: Server errors.createDataGridSelector<TData>(): returns a typed raw store selector hook. Create the hook once at module scope and name ituse…, for exampleconst useOrderSelector = createDataGridSelector<Order>().TDatatypesstate.data, so a selector that reads rows gets them back typed. The hook takes(selector, eq?);eq(defaultObject.is) controls re-renders.DataGridStoreStateOf<TData>is the state type the selector receives.useDataGridRow<TData>(viewRowIndex): the typed row at a view (display) index. OmitTDataforunknown, the previous shape.
onSelectionChange, onColumnLayoutChange, and every other event source are covered in full on
Events & state.
ColumnDef<TData, TValue>
Prop
Type
Prefer defineColumns over typing ColumnDef[] by hand
defineColumns<TData>()([...]) infers TValue per column from accessorKey or accessorFn,
and narrows options and validate through the cell type's key in GridCellTypes, catching
accessorKey typos and type-key typos at compile time. See
Quick start.
AnyColumnDef (ColumnDef<unknown, unknown, any>) is the row-agnostic shape that the store and
its hooks (useDataGridVisibleColumns(), useDataGridAllColumns(), and similar hooks) actually
traffic in. Reach for it when you write custom column UI that does not know its TData generic.
validate's type: a union, and a 3rd type parameter
validate is ((value: TValue, row: TData) => string | null) | StandardSchemaV1<TValue>: the
function form, or any Standard Schema. ColumnDef has a 3rd type
parameter, TValidate (defaults to TValue), because the function-or-schema union does not
stay assignable when the row-agnostic AnyColumnDef erases its type parameters to unknown.
So AnyColumnDef erases TValidate to any instead. This never affects how you author
validate on a concretely-typed column through defineColumns. StandardSchemaV1.InferInput<S>
and InferOutput<S> are exported from types.ts for inspecting a schema's own input and output
types.
CellType<TData, TValue, TOptions>
Prop
Type
Register custom types through the cellTypes prop of DataGridProvider. The prop merges over
the built-ins (text, number, checkbox, select, date): unnamed built-ins keep working,
a key that names a built-in replaces it, and a key set to null removes that type. Wrap the type
in defineCellType(key, type) once your GridCellTypes augmentation is in place: it checks the
key and the type's value/options against the augmentation at the definition, and returns the
entry as-is. See Recipes for a worked example.
GridCellTypes
This interface map gives defineColumns its per-type inference. Augment it through declaration
merging in your own module to give a custom cell type the same compile-time options and value
narrowing as the built-ins:
declare module "@/components/data-grid/types" {
interface GridCellTypes {
currency: { value: number | null; options: { currency: string } };
}
}Adjust the module path to wherever your components.json aliases actually placed types.ts.
defineCellType(key, type)
A compile-time gate for a custom cell type: key must be a cell-type key of GridCellTypes
(including your augmentation), and type must match that key's declared value and options.
It costs nothing at runtime and returns the entry unchanged, ready for the cellTypes registry.
useCellEditor(props, codec)
The text-input editor primitive the built-in text and number editors are built from. It owns
the draft state (seeded from props.initialText, or codec.toDraft(value) when there is
none), the end-caret focus, and the one-shot commit guard (re-armed when rejectionCount
rises). It also binds Enter (commit, move down), Escape (cancel), and blur (commit in place).
During IME composition, Enter and Escape do nothing. codec is { toDraft, toValue }. toValue
must never throw and must return your type's clearValue result for text it cannot parse. The
hook returns { ref, value, onChange, onKeyDown, onBlur, readOnly, "aria-label", "aria-busy", dir }.
Spread the bindings onto your input and pass its ref. readOnly mirrors props.pending,
aria-label is the column label, aria-busy is true while props.pending is true, and dir
is "auto".
DataGridLabels
This groups every user-facing string, across the core and every add-on, by owning surface. Pass
a DeepPartialLabels override to the labels prop of DataGridProvider. See
i18n.
Prop
Type
Other exported types
DataGridApi<TData>: the imperative handle of one grid:actions,store,scrollTo,focus,startEditing,stopEditing,getSelection,setSelection,getRow, andgetViewRowIds. From<DataGrid ref>or fromuseDataGridApi. See Imperative handle.CellRef({ rowId, columnId }): the stable identity of a cell: yourgetRowIdvalue plus a column id. Sorting, filtering, and reordering never change it. Cell actions take aCellRefby default; each also has an*Atvariant that takes aViewCoordinstead.CellRange({ start: CellRef; end: CellRef }): the two opposite corners of a rectangular selection; either diagonal order.SelectionState({ anchor, range, rangeStack, rowIds, columnIds }): the selection in stableCellRefterms: theonSelectionChangepayload, theselection/defaultSelectionprop value, and thesetSelection/getSelectionarguments. The active cell is deliberately not part of it. See Events & state.ViewCoord({ col, row }): view-index: the sorted/filtered row position, not adataindex. It moves when the view changes.ViewCellRef({ rowId, columnId, viewRowIndex, viewColumnIndex }): aCellRefplus the view position the cell occupied when an event fired.onActiveCellChange,onEditStart, andonEditEnddeliver it.GridRect({ x, y, width, height }, half-open).GridSelection({ current: {cell, range, rangeStack} | null, rows, columns }).DataOp<TData>(update,insert,delete, ormove, row-id-based) andDataChange<TData>({ ops, source }).SortSpec({ columnId, direction }),FilterSpec, andFilterOperator.CellTypeFilter({ operators?, match?, valueInput? }),CellTypeValueInput("text" | "number" | "date" | "boolean" | "choices"), andFilterValueInputProps(the props of a customvalueInputcomponent), the filter capabilities a cell type declares. See custom cell types.GridActions(the named keyboard actions, as an interface you can extend by declaration merging) andGridAction(every named keyboard action, the built-ins plus any you merged in) andKeymap(Partial<Record<GridAction, KeyBinding[]>>).GridCommand<TData>({ run, when?, scope?, label?, group? }) andGridCommandCtx<TData>({ api, cell, viewRowIndex, viewColumnIndex, row, readOnly }): the custom-command contract behind thecommandsprop.scopeselects when the command dispatches ("grid","editing","always"), andCommandGroupnames the keybindings dialog's sections. See Keybindings: Custom commands.RowMarkersMode,HeaderClickBehavior, andDensityMode.ColumnLayout({ widths, order, pins, hidden }): the full layout snapshot: theonColumnLayoutChangepayload, and the shape of thecolumnLayout/defaultColumnLayoutprops inPartialform. See Events & state.DataGridPlugin<TData>({ name, Overlay?, rowBands?, onDataChange?, commands?, keymap?, Mount? }),PluginRowBands({ top?, bottom?, render }),RowBandRenderCtx,DataGridPluginCtx<TData>({ api }), andOverlayPluginCtx: the plugin members and their contexts. See Plugins for the full contract and a worked example, and Multiplayer presence, Fill handle, Undo & redo, and Pinned rows for the first-party consumers.CellErrorEntry({ rowId, columnId, message }) andCellErrorTarget({ rowId, columnId }), the input shapes foractions.setCellErrors/actions.clearCellErrors. See Editing & cell types: Server errors.GridEditEndEvent({ rowId, columnId, viewRowIndex, viewColumnIndex, result: "commit" | "cancel" | "rejected" }),GridValidationErrorEvent({ source: "paste" | "fill", rejected }), andGridBulkValidationError({ rowId, columnId, viewRowIndex, value, message }), the payloads ofonEditEndandonValidationError. See Events & state.
createFilterMatcher(filter) pre-parses the bounds of a FilterSpec once
and returns a reusable (text: string) => boolean matcher. This has the same semantics as
matchesFilter, but without re-parsing the filter's value on every row.
Operation engine
The core applies every DataChange batch through one engine. The data-grid barrel exports it
for consumers who apply operations to their own copy of the data:
applyChange(data, change, getRowId): applies a batch to a row array and returns a new array, in O(n + k log(n + k)) fornrows andkoperations. Amoveoperation applies as a delete plus an insert atto.- Row-id-based, missing-id skip.
updateanddeleteoperations locate the row byrowId, never by the operation's stored index. If the row id is no longer present, that operation is skipped, not an error. - Snapshot indices. Each operation's
indexis the row's position in the array as it stood before the whole batch, not a running position updated one operation at a time.insertoperations apply in ascending index order, so a multi-row batch round-trips throughinvertChange. invertChange(change): returns the change that undoes a batch. Each operation is inverted:updateswapsrow/prev,insertbecomesdeleteand back,moveswapsfrom/to. The operation order is reversed, so a batch unwinds in the correct dependency order.
The grid's onDataChange and the data-grid-history add-on run this same engine. A consumer
cache that applies operations with applyChange stays in step with the grid and with undo.
Add-on option types
Each add-on's public props follow the same source-of-truth convention. These are the ones you will reach for most:
DataGridUrlStateProps
Prop
Type
UseDataGridStateOptions
This is the options object for useDataGridState, the uncontrolled quick-start hook from
data-grid-history. See Quick start.
Prop
Type
UseDataGridHistoryOptions
This is the options object for useDataGridHistory, the composable history hook of
data-grid-history (it takes data and setData, mirroring the useState tuple). See
Undo & redo.
Prop
Type
DataGridContextMenuProps
DataGridExportButtonProps
UseDataGridLazyRowsOptions
This is the options object for useDataGridLazyRows from data-grid-lazy. See
Lazy loading.
Prop
Type
UseDataGridLazyRowsResult
This is the return shape of useDataGridLazyRows from data-grid-lazy. See
Lazy loading.
Prop
Type
DataGridPaginationControls / DataGridPaginationBarProps
This is the return shape of useDataGridPagination (client and server mode alike) and the props
of the composable footer bar. See Pagination.
Prop
Type
UseDataGridFillOptions
This is the options object for useDataGridFill from data-grid-fill. See
Fill handle.
Prop
Type
UseDataGridPinnedRowsOptions
This is the options object for useDataGridPinnedRows from data-grid-pinned-rows. See
Pinned rows.
Prop
Type