Grid options
These are the primary options shared by the core, React props, and Angular inputs. Optional fields use documented defaults when omitted.
Data and identity
| Option | Type | Purpose |
|---|---|---|
columnDefs | ColDef[] | Column and column-group definitions |
rowIdKey | string | Field containing a stable row ID |
getRowId | (row) => string | Derive a stable row ID |
rowDataMode | auto | reset | diff | Whether a replacement rowData array is diffed into the grid (keeping history and page) or re-ingested. Default auto |
asyncTransactionWaitMs | number | Batch window for applyTransactionAsync; defaults to 16 ms. 0 flushes on the next macrotask |
rowModelType | clientSide | serverSide | Select the row model |
serverSideDataSource | IServerSideDataSource | Lazy data-source contract |
serverSideBlockSize | number | Requested block size |
React and Angular expose rowData through their bindings; core integrations use
api.setRowData().
Layout and columns
| Option | Type | Default |
|---|---|---|
rowHeight | number | Theme/default row height |
headerHeight | number | Theme/default header height |
overscanRowCount | number | Viewport-derived default |
rowNumbers | boolean | false |
defaultColDef | DefaultColDef | {} |
minResizeWidth | number | 75 |
maxColumnWidth | number | 420 |
columnPanel | boolean | ColumnPanelOptions | false |
Interaction
| Option | Type | Default |
|---|---|---|
cellSelection | boolean | "text" | true (false/"text" also disable the body keyboard cursor — navigation, clipboard, and editing keys) |
rangeSelection | boolean | true |
columnSelection | boolean | true |
headerKeyboardNavigation | boolean | true (false makes header sort/menu/selection mouse-only) |
rowSelection | boolean | RowSelectionOptions | false (object form configures mode and the checkbox column) |
selectAllScope | "filtered" | "page" | "filtered" (select-all and areAllRowsSelected span the whole filtered set) |
selectionPersistence | "clear" | "keep" | "clear" (row selection on filter/sort/quick-filter changes) |
selectAllRowsOnHeaderClick | boolean | false |
clearSelectionOnBodyClick | boolean | true |
highlightActiveCell | boolean | false |
bodyContextMenu | boolean | getter | true |
rowInsertionMenu | RowInsertionMenuOptions | Not set; opt-in Insert submenu on client-side row numbers |
RowSelectionOptions accepts mode: "single" | "multiple" (default
"multiple"), checkboxes, and headerCheckbox. Single mode always hides the
header checkbox. Checkbox-column placement uses two independent options:
checkboxColumnPinned: "left" | "right" | null chooses its initial position
(default "left"), while checkboxColumnPinnable controls whether users can
change that position later (default true).
These nested row-selection options reconcile live in both React and Angular;
changing them does not remount the grid or replace its API instance.
Editing
| Option | Type | Default |
|---|---|---|
editTrigger | doubleClick | singleClick | none | doubleClick |
suppressKeyboardEdit | boolean | false |
suppressTypeToEdit | boolean | false |
moveAfterEdit | boolean | true |
commitOnBlur | boolean | true |
reevaluateOnEdit | boolean | true |
undoLimit | number | 100 |
Sort, filter, and pagination
| Option | Type | Purpose |
|---|---|---|
initialSort | { colId, dir }[] | Ordered initial client-side sort |
showSortPriority | multi | always | never | Priority badge behavior |
quickFilter | boolean | QuickFilterOptions | Global client-side search |
filterDebounceMs | number | Default column-filter debounce |
pagination | boolean | Enable footer pagination |
paginationControls | PaginationControlsOptions | Page-picker style plus visible pagination controls and their order |
pageSize | number | Initial page size |
pageSizes | number[] | User-selectable page sizes |
resetPageOn | ("filter" | "sort" | "quickFilter")[] | Model changes that jump back to page 1 (default []) |
pageSizes is normalized at init (sorted ascending, non-positive entries
dropped). If pageSize is not in the list it is added automatically so the
page-size selector can display it — with a console warning when pageSizes was
set explicitly.
The page picker remains a <select> by default. Use numbered buttons and configure
the footer controls by supplying their visual (and keyboard) order:
paginationControls: {
pageSelection: "buttons",
showPageLabel: false,
controls: ["previousPage", "pageSelector", "nextPage", "pageSize"],
maxPageButtons: 7,
}
Available controls are "pageSize", "firstPage", "previousPage",
"pageSelector", "nextPage", and "lastPage". Omitted controls are hidden.
Set showPageLabel: false to remove the visible Page label while preserving
accessible names on the select or numbered-button group.
Numbered pagination keeps the first and last known pages visible, centers a bounded
window around the current page, and inserts ellipses when pages are skipped.
The footer adapts to its own width, on the same ladder the toolbar uses — see
Narrow bars. Its rungs, cheapest first: the text beside each control
("Rows per page", "Aggregate", "Page") is hidden; the first and last page buttons
go, since the page picker beside them already reaches any page; rows-per-page moves into
the footer's overflow menu; then the aggregate scope; then the sheet strip's +. Page
navigation itself never gives way — a footer that cannot page is not a footer — so a
footer still short of room scrolls instead. Trimming controls is how an application
spends that width on something else — a wide sheet-tab strip, for instance.
paginationControls: { responsive: "collapse" } // "collapse" (default) | "scroll" | false
Filter and quick-filter changes used to reset pagination to page 1 (and sort
changes never did). The default is now resetPageOn: [] — no model change
resets the page. The grid keeps the user's current page; when the change
shrinks the row count past it, it clamps to the last page instead of showing
an empty view. Add "filter", "quickFilter", and/or "sort" to restore the
jump-to-page-1 behavior for that trigger — the policy is now symmetric and
per-trigger. (On the server-side row model the page snaps back once the total
row count is known; the quick filter is client-side only.)
Grouping and hierarchy
| Option | Type | Purpose |
|---|---|---|
groupDisplayType | singleColumn | multipleColumns | groupRows | Label layout |
groupDefaultExpanded | number | Initial expanded depth; -1 means all |
groupSortMode | local | hierarchy | global | Client-side group ordering |
groupRowsSelectable | boolean | Include generated groups in selection |
groupRowsSticky | boolean | Dock the active ancestor chain |
treeData | TreeDataOptions | Enable path, parent, or children hierarchy |
pivotMode | boolean | Start in pivot mode (client-side; exclusive with tree data). Live in both wrappers — a prop/input change toggles the mode |
pivotColumns | string[] | Columns to pivot on, by colId, in level order. Live in both wrappers |
pivotResultColumnDef | Partial<ColDef> | Overlay for every generated pivot value column |
maxPivotColumns | number | Cap on generated pivot columns (default 200; truncates + fires pivotColumnLimitReached). A target, not an exact ceiling — truncation is per pivot value, so the count can land under or over it |
pivotColumnMoveMode | "measures" | "free" | What dragging a generated pivot column does: reorder the measures everywhere (default) or arrange leaves freely, splitting groups (updatable at runtime) |
Presentation and integration
| Option | Type | Purpose |
|---|---|---|
theme | GridTheme | Per-instance visual theme |
icons | GridIconMap | Named icon overrides |
tooltip | boolean | TooltipOptions | Global tooltip behavior |
getRowPresentation | (params) => RowPresentation | Row/cell styling defaults, tooltip defaults, editability, ARIA description/busy state, and metadata |
toolbar | GridToolbarOptions | Opt-in toolbar sections, plus responsive (see Narrow bars) |
savedViews | SavedViewsOptions | Application-owned view persistence |
sheets | SheetsOptions | Spreadsheet-style footer tabs (Data + pivot sheets over one row model); application-owned list |
suppressStyleInjection | boolean | Use imported CSS instead |
styleNonce | string | CSP nonce for injected styles |
loadingMessage | string | Loading overlay copy |
noRowsMessage | string | Empty-data copy |
pivotNoValuesMessage | string | Copy of the header hint shown while pivot mode has no aggregates |
Narrow bars
Both bars — the toolbar above the header and the footer below the body — cope with a width
their controls do not fit by the same rule: nothing is ever clipped, overlapped, or
compressed. Every control is laid out at its natural size in one of its presentation
stages, or it moves into that bar's overflow menu (⋮); a bar that runs out of stages
scrolls, so nothing becomes unreachable.
The toolbar's rungs, cheapest first:
- every button caption at once — the tooltip on each button carries the label it lost;
- the quick-filter input narrows — a field you can still read and type in costs less than the name of a column you grouped by;
- Grouped by / Sort by chips fold from the end into a
+Nchip, one at a time; - each chip section becomes a summary button (
Grouped by 3) that opens the same drag-reorder editor as a popover — and stays a drop target for a column dragged out of the header; - Export, Pivot, Views, then the two chip sections move into the
⋮; - the quick filter becomes a search icon that expands the box back over the bar in place;
- Columns last, because the column panel is the escape hatch to everything else.
Two rules keep that honest. A control that holds focus, or that carries state the user is
relying on (a quick filter with a query), is not displaced — the next rung goes
instead — so nothing collapses out from under someone mid-use. And when something is
displaced, its state does not vanish quietly: the ⋮ wears a dot while anything inside it
is active, and focus follows a displaced control to the button that now holds it.
A settled bar has no hole in it. The last rung applied usually frees more room than was needed, and rather than leaving that as blank space in the middle of the bar, one control takes it: the search field, which stretches into it (up to a limit), or — with no quick filter configured — the last chip section, which widens its drop zone instead.
The order is fixed. An application that wants a different one configures fewer controls rather than re-ordering the ladder; every ordering is a degradation path that has to hold up at every width. What is configurable is whether the ladder runs at all:
toolbar: { grouping: true, sorting: true, quickFilter: true, responsive: "collapse" }
"collapse" (the default) walks the ladder above. "scroll" leaves every control at full
size and scrolls the bar as soon as they do not fit — simplest to reason about, at the cost
of controls sitting off-screen. false lays the bar out and lets it clip, for an
application that guarantees its own width. paginationControls.responsive says the same
for the footer.
The package's TypeScript declarations remain the source of truth for less common callbacks and detailed nested option types.
Row presentation
Use getRowPresentation when a status belongs to the whole row rather than a
particular field:
getRowPresentation: ({ rowId }) => {
const error = errors.get(rowId);
if (!error) return undefined;
return {
rowClass: "row-error",
cellClass: "cell-in-error-row",
cellStyle: { backgroundColor: "var(--error-row-bg)" },
editable: false,
tooltip: {
content: error.message,
component: ErrorTooltip,
componentParams: { showCode: true },
options: { mode: "follow", escapeRootClip: true },
},
accessibility: {
description: `Row contains an error: ${error.message}`,
busy: false,
},
metadata: { status: "error", error },
};
}
rowClass/rowStyle style every row-container fragment and compose with the
older getRowClass/getRowStyle hooks. cellClass is combined with each
column's cellClass; cellStyle is the default object and the column wins only
conflicting properties. The resolved presentation is also available to cell
renderers, cell-style callbacks, and tooltip components as rowPresentation.
editable: false prevents user editing throughout the row. It is a veto: the
row cannot make a column editable unless that column is already editable, and
a column with editable: false remains non-editable. For a deliberate exception,
set inheritRowPresentation.editable: false on that column. Programmatic writes
through setCellValue and setCellValues are not blocked by UI editability.
Tooltip layers resolve by specificity:
- Content: explicit column getter/field → row content →
defaultColDef→ clipped-cell text. - Component: explicit column component → row component →
defaultColDef→ built-in text. - Options, field by field: grid →
defaultColDef→ row → explicit column.
This lets a column replace its message or placement while retaining the row's
component and other behavior. interactive: true always forces anchored mode;
placement is relevant only while anchored. A column can opt out selectively:
{
key: "actions",
label: "Actions",
inheritRowPresentation: {
tooltip: false,
cellClass: false,
cellStyle: false,
editable: false,
},
}
When the callback reads external state (a pending-ID set, for example), call
api.refreshRowPresentation() after changing it. Row transactions already
repaint affected rendered rows. React and Angular row tooltip components use
the framework-aware ReactGetRowPresentation and NgGetRowPresentation types.