-
Notifications
You must be signed in to change notification settings - Fork 0
Tree Data and Grouping
📝 Generated from
docs/features/tree-data-grouping.md. Edit it there; changes made in the wiki are overwritten.
Display complex, hierarchical data structures with ease.
Row grouping allows you to categorize rows based on common column values.
<DataGrid
rows={rows}
columns={columns}
rowGroupingModel={['department', 'role']}
/>-
Multi-Level Groups: Nest data as deeply as needed — one level per field in
rowGroupingModel, in order. - Aggregation Integration: Summarize values automatically for each group level.
-
Expansion Control:
defaultGroupingExpansionDepthsets how many levels start expanded (default0: all collapsed;-1: everything expanded). -
Aggregate placement:
getAggregationPosition(node)returns'inline'(on the group row, the default),'footer'(a subtotal row after the group's children while it is expanded) ornull(hidden). It is also called once withnullfor the grand-total footer row; returningnullthere hides the footer.
-
Pagination is ignored while
rowGroupingModelis active. All groups render in one scrollable, virtualized view, so the grid needs a bounded height (Virtualization). A development-mode warning is logged if you passpaginationtoo. -
Expansion state survives data updates (row grouping and tree data). Groups and nodes the user expanded or collapsed stay that way when
rowschanges: inline edits, live refreshes, new array identities, and lazily loaded server-side children. The state resets todefaultGroupingExpansionDepthonly whenrowGroupingModelordefaultGroupingExpansionDepthchanges value. -
Group aggregation uses the same functions as the footer.
sum,avg,count,min,maxanduniqueignorenull/undefined, so a group of[10, null, 20]givesmin10,avg15 andcount2.availableAggregationFunctionson a column is honoured for group rows too. -
The expand toggle, indentation and group label sit in the leftmost column on screen, after column order, visibility and pinning are applied — not in whichever column is first in
columns. Hiding or moving that column no longer leaves group rows without a label or toggle (fixed in v3.0). -
Keyboard and screen readers (v3.0): Enter on a non-editable cell of a group row or a tree-data parent expands or collapses it, and Alt+ArrowRight / Alt+ArrowLeft expand / collapse it. Rows expose
aria-level(depth + 1), and rows with children exposearia-expanded. The expand buttons inside cells are not separate Tab stops. See Keyboard & Accessibility. -
valueFormatterapplies to grouped rows the same as flat rows (fixed in v2.1; earlier versions rendered raw values for every column once grouping was on). -
Group subtotals and the
(n)count follow the filter. They cover only the leaf rows that pass the current filter, and groups with no matching row are left out (v3.0; before, they counted hidden rows too). Groups keep their order of first appearance while filtering. -
Grouping values are compared by value, not by text:
nulland'null',1and'1',trueand'true'are separate groups; equal dates share one. A column with avalueGetteris grouped by the value it computes. -
groupable: falsefields are dropped from the model before grouping, so the other levels keep their depth, indentation,defaultGroupingExpansionDepthand export depth. - Sorting the column that shows the group labels orders the groups by their grouping value; sorting an aggregated column orders them by the aggregate.
-
Group rows are synthetic. They have no selection checkbox and no detail panel, their ids never appear in the selection model, clicking them toggles them (without
onRowClick), and a column'svalueGetteris not called for them.renderCellis called for them: see GridRowMeta. -
Server modes: with
filterMode="server"/sortingMode="server"the grid does not filter or sort the rows again on the client, in row grouping and tree data as in a flat grid. -
Pass stable callbacks.
rowGroupingModelandaggregationModelare compared by value, so inline arrays and objects are fine, but a newgetTreeDataPathorcolumnsidentity on every render rebuilds the whole hierarchy. Define them at module scope or memoize them.
Tree data is used for data that has a natural parent-child relationship (e.g., an organizational chart or file system).
- Enable
treeData={true}. - Provide a
getTreeDataPathfunction to define the hierarchy. It is required: without it the rows are shown flat. Define it at module scope or withuseCallback.
<DataGrid
rows={rows}
columns={columns}
treeData
getTreeDataPath={getPath} // e.g. (row) => row.hierarchyPath: ['CEO', 'VP Engineering', 'Manager']
/>-
Path segments can contain any character, including
/:['a/b']and['a', 'b']are different paths. -
Missing parents are created for you. A path segment with no row of its own gets a synthetic parent row (
rowMeta.isGroupRow, label inrowMeta.groupLabel, row object{ id }) shown in the toggle column aslabel (n), whatever that column is called. It is shown only when a row under it passes the filter, and sorting the toggle column orders it by its label. -
Parents that are your own rows behave like any row: clicking one fires
onRowClickand selects it; its chevron expands it. (Before v3.0 a click toggled it and never firedonRowClick.) From the keyboard it expands with Enter or Alt+ArrowRight (see below) and Shift+Space selects it. -
descendantCount(the(n)) counts the rows below a node at any depth that pass the filter. A parent whose children are all filtered out is shown without a toggle. -
Invalid paths are reported in development: a row whose path is empty is shown as a top-level row, rows sharing a path attach their children to the first of them, and
treeDatawithoutgetTreeDataPathshows the rows flat. Each logs aconsole.warn. - Pagination pages the flattened visible tree; keyboard navigation stays on the current page.
-
Lazy (server) trees: the children of an expanded node with
serverChildrenCountare fetched when it is expanded, and fetched again after a server re-fetch (a sort or filter change) replaces the rows.defaultGroupingExpansionDepthcounts such a node as expandable (v3.0+), so-1expands every lazy node and loads its children. -
apiRef.getAllFilteredRows()with a filter returns the rows that match the filter, the same set select-all and the aggregation footer use. Ancestors shown only to give a match its context are not in it (v3.0+; before, they were). -
Row grouping with
paginationMode="server": grouping turns pagination off, so adataSourceis asked for every row (see Data Source).
| Prop | Type | Default | Description |
|---|---|---|---|
rowGroupingModel |
string[] |
[] |
Fields to group by (in order). |
treeData |
boolean |
false |
Enable tree data mode. |
getTreeDataPath |
(row) => string[] |
undefined |
Path of a row. Required with treeData. |
defaultGroupingExpansionDepth |
number |
0 |
How many levels start expanded (0 = collapsed, -1 = all). |
groupingColDef |
Partial<GridColDef<R>> |
undefined |
Adds a dedicated group column (row grouping or tree data). |
getAggregationPosition |
(node: GridTreeNode | null) => 'inline' | 'footer' | null |
undefined |
Where group aggregates appear; called with null for the grand total. |
Hierarchy information is never written onto your row objects: read it from params.rowMeta (isGroupRow, hasChildren, treeDepth, groupLabel, …) in renderCell. See GridRowMeta.
When rowGroupingModel or treeData is active, pass groupingColDef to configure a dedicated __group__ column that is prepended at position 0 and auto-pinned left, separate from your data columns. Its type is Partial<GridColDef<R>>: every key is optional, and a field you pass is ignored (it is always '__group__'). It also forces hideable, sortable, filterable, pinnable and exportable to false. Defaults: headerName: 'Group', width: 220. With tree data (v3.0) the column shows the last segment of each row's path, and a valueGetter in groupingColDef can show something else (for example the whole path).
<DataGrid
rows={rows}
columns={columns}
rowGroupingModel={['department']}
groupingColDef={{
headerName: 'Department Group',
width: 240,
}}
/>Without groupingColDef, the group toggle is overlaid on the leftmost column on screen. With it, the group indicator always appears in its own fixed column regardless of your columns order. A renderCell in groupingColDef renders the group rows' label cell (return undefined to keep the default label).
By default each group-header row displays "field: value". Use groupingValueFormatter on a GridColDef to override the label for that grouping level:
const columns: GridColDef[] = [
{
field: 'department',
headerName: 'Department',
groupingValueFormatter: ({ value }) => `📁 ${String(value)}`,
},
{ field: 'name', headerName: 'Name' },
{ field: 'salary', headerName: 'Salary' },
];
<DataGrid rows={rows} columns={columns} rowGroupingModel={['department']} />
// Group headers now show: "📁 Engineering", "📁 HR", etc.Set groupable: false on a GridColDef to prevent that field from being used as a grouping dimension. The column still renders normally, but the grid skips it when building the group tree:
const columns: GridColDef[] = [
{ field: 'id', headerName: 'ID', groupable: false },
{ field: 'department', headerName: 'Department' },
];
// Even if rowGroupingModel includes 'id', it will be silently skipped.
<DataGrid rows={rows} columns={columns} rowGroupingModel={['id', 'department']} />
// Result: grouped by 'department' only — 'id' is skipped.OpenGridX 3.2.2 · MIT · This wiki is generated from docs/ on every push to main. To fix a page, open a PR against the source file.
Start here
Components
- DataGrid
- Header
- Row
- Cell
- Toolbar
- Pagination
- Filter Panel
- Tooltip
- Column Visibility
- Column Grouping
- Column Resizing
- Empty State
- Error Overlay
- Aggregation Footer
Features
- Virtualization
- Filtering & Search
- Sorting & Pagination
- Custom Pagination
- Editing & Reordering
- Row Selection
- Clipboard
- Pinning
- State Persistence
- Aggregation & Pivot
- Tree Data & Grouping
- Cell Spanning
- Master-Detail
- Keyboard & Accessibility
- List View
- Infinite Scroll
- Data Source
- Loading States
- Toolbar Customization
- Export (CSV, Excel, JSON, Print)
- PDF Export
Customization
Upgrading
Contributing
- Contributing
- Testing
- Roadmap
- DataGrid orchestration
- GridRowMeta
- useGridControlledState
- useGridRowPipeline
- useGridColumns
- useGridVirtualization
- useGridVisibleRows
- useGridScrollSync
- useGridStateSnapshot