Data Grid - Group & Pivot
Use grouping, pivoting, and more to analyze the data in depth.
Row grouping
For when you need to group rows based on repeated column values, and/or custom functions.
On the following example, we're grouping all movies based on their production company
⚠️ This feature is temporarily available on the Pro plan until the release of the Premium plan.
To avoid future regression for users of the Pro plan, the feature needs to be explicitly activated using the
rowGroupingexperimental feature flag.<DataGridPro experimentalFeatures={{ rowGrouping: true }} {...otherProps} />The feature is stable in its current form, and we encourage users willing to migrate to the Premium plan once available to start using it.
Set grouping criteria
Initialize the row grouping
The easiest way to get started with the feature is to provide its model to the initialState prop:
initialState={{
rowGrouping: {
model: ['company', 'director'],
}
}}
The basic parameters are the columns you want to check for repeating values. In this example, we want to group all the movies matching the same company name, followed by a second group matching the director's name.
Controlled row grouping
If you need to control the state of the criteria used for grouping, use the rowGroupingModel prop.
You can use the onRowGroupingModelChange prop to listen to changes to the page size and update the prop accordingly.
Grouping columns
Single grouping column
By default, the grid will display a single column holding all grouped columns. If you have multiple grouped columns, this column name will be set to "Group".
Multiple grouping column
To display a column for each grouping criterion, set the rowGroupingColumnMode prop to multiple.
Custom grouping column
To customize the rendering of the grouping column, use the groupingColDef prop.
You can override the headerName or any property of the GridColDef interface, except the field, the type and the properties related to inline edition.
By default, when using the object format, the properties will be applied to all Grouping columns. This means that if you have rowGroupingColumnMode set to multiple, all the columns will share the same groupingColDef properties.
If you wish to override properties of specific grouping columns or to apply different overrides based on the current grouping criteria, you can pass a callback function to groupingColDef, instead of an object with its config.
The callback is called for each grouping column, and it receives the respective column's "fields" as parameter.
Show values for the leaves
By default, the grouped rows display no value on their grouping columns' cells. We're calling those cells "leaves".
If you want to display some value, you can provide a leafField property to the groupingColDef.
Hide the descendant count
Use the hideDescendantCount property of the groupingColDef to hide the number of descendants of a grouping row.
Disable the row grouping
For all columns
You can disable row grouping by setting disableRowGrouping prop to true.
It will disable all the features related to the row grouping, even if a model is provided.
For some columns
In case you need to disable grouping on specific column(s), set the groupable property on the respective column definition (GridColDef) to false.
In the example below, the director column can not be grouped. And in all example, the title and gross columns can not be grouped.
Using groupingValueGetter for complex grouping value
The grouping value has to be either a string, a number, null or undefined.
If your cell value is more complex, pass a groupingValueGetter property to the column definition to convert it into a valid value.
const columns: GridColumns = [
{
field: 'composer',
groupingValueGetter: (params) => params.value.name,
},
// ...
];
Note: If your column also have a valueGetter property, the value passed to the groupingValueGetter method will still be the row value from the row[field].
Rows with missing groups
If the grouping key of a grouping criteria is null or undefined for a row, the grid will consider that this row does not have a value for this group. and will inline it for those groups.
Group expansion
By default, all groups are initially displayed collapsed. You can change this behaviour by setting the defaultGroupingExpansionDepth prop to expand all the groups up to a given depth when loading the data.
If you want to expand the whole tree, set defaultGroupingExpansionDepth = -1
If you want to expand groups by default according to a more complex logic, use the isGroupExpandedByDefault prop which is a callback receiving the node as an argument.
When defined, this callback will always have the priority over the defaultGroupingExpansionDepth prop.
isGroupExpandedByDefault={
node => node.groupingField === 'company' && node.groupingKey === '20th Century Fox'
}
Use the setRowChildrenExpansion method on apiRef to programmatically set the expansion of a row.
Sorting / Filtering
Single grouping column
When using rowGroupingColumnMode = "single", the default behavior is to apply the sortComparator and filterOperators of the top level grouping criteria.
If you are rendering leaves with the leafField property of groupColDef, the sorting and filtering will be applied on the leaves based on the sortComparator and filterOperators of their original column.
In both cases, you can force the sorting and filtering to be applied on another grouping criteria with the mainGroupingCriteria property of groupColDef
⚠️ This feature is not yet compatible with
sortingMode = "serverandfilteringMode = "server"
Multiple grouping column
When using rowGroupingColumnMode = "multiple", the default behavior is to apply the sortComparator and filterOperators of the grouping criteria of each grouping column.
If you are rendering leaves on one of those columns with the leafField property of groupColDef, the sorting and filtering will be applied on the leaves for this grouping column based on the sortComparator and filterOperators of the leave's original column.
If you want to render leaves but apply the sorting and filtering on the grouping criteria of the column, you can force it by setting the mainGroupingCriteria property groupColDef to be equal to the grouping criteria.
In the example below:
- the sorting and filtering of the
companygrouping column is applied on thecompanyfield - the sorting and filtering of the
directorgrouping column is applied on thedirectorfield even though it has leaves
⚠️ If you are dynamically switching the
leafFieldormainGroupingCriteria, the sorting and filtering models will not automatically be cleaned-up and the sorting / filtering will not be re-applied.
Full example
addRowGroupingCriteria()
Adds the field to the row grouping model.
Signature:
addRowGroupingCriteria: (groupingCriteriaField: string, groupingIndex?: number) => voidremoveRowGroupingCriteria()
sRemove the field from the row grouping model.
Signature:
removeRowGroupingCriteria: (groupingCriteriaField: string) => voidsetRowGroupingCriteriaIndex()
Sets the grouping index of a grouping criteria.
Signature:
setRowGroupingCriteriaIndex: (groupingCriteriaField: string, groupingIndex: number) => voidsetRowGroupingModel()
Sets the columns to use as grouping criteria.
Signature:
setRowGroupingModel: (model: GridRowGroupingModel) => voidTree Data
Tree Data allows to display data with parent/child relationships.
To enable the Tree Data, you simply have to use the treeData prop as well as provide a getTreeDataPath prop.
The getTreeDataPath function returns an array of strings which represents the path to a given row.
// The following examples will both render the same tree
// - Sarah
// - Thomas
// - Robert
// - Karen
const columns: GridColumns = [{ field: 'jobTitle', width: 250 }];
// Without transformation
const rows: GridRowsProp = [
{ path: ['Sarah'], jobTitle: 'CEO', id: 0 },
{ path: ['Sarah', 'Thomas'], jobTitle: 'Head of Sales', id: 1 },
{ path: ['Sarah', 'Thomas', 'Robert'], jobTitle: 'Sales Person', id: 2 },
{ path: ['Sarah', 'Thomas', 'Karen'], jobTitle: 'Sales Person', id: 3 },
];
<DataGridPro
treeData
getTreeDataPath={(row) => row.path}
rows={rows}
columns={columns}
/>;
// With transformation
const rows: GridRowsProp = [
{ path: 'Sarah', jobTitle: 'CEO', id: 0 },
{ path: 'Sarah/Thomas', jobTitle: 'Head of Sales', id: 1 },
{ path: 'Sarah/Thomas/Robert', jobTitle: 'Sales Person', id: 2 },
{ path: 'Sarah/Thomas/Karen', jobTitle: 'Sales Person', id: 3 },
];
<DataGridPro
treeData
getTreeDataPath={(row) => row.path.split('/')}
rows={rows}
columns={columns}
/>;
Custom grouping column
Same behavior as for the Row grouping except for the leafField and mainGroupingCriteria which are not applicable for the Tree Data.
Accessing the grouping column field
If you want to access the grouping column field, for instance, to use it with column pinning, the GRID_TREE_DATA_GROUPING_FIELD constant is available.
<DataGridPro
treeData
initialState={{
pinnedColumns: {
left: [GRID_TREE_DATA_GROUPING_FIELD],
},
}}
{...otherProps}
/>
Group expansion
Same behavior as for the Row grouping.
Gaps in the tree
If some entries are missing to build the full tree, the DataGridPro will automatically create rows to fill those gaps.
Filtering
A node is included if one of the following criteria is met:
- at least one of its descendant is passing the filters
- it is passing the filters
By default, the filtering is applied to every depth of the tree.
You can limit the filtering to the top-level rows with the disableChildrenFiltering prop.
Sorting
By default, the sorting is applied to every depth of the tree.
You can limit the sorting to the top level rows with the disableChildrenSorting prop.
If you are using
sortingMode="server", you need to always put the children of a row after its parent. For instance:// ✅ The row A.A is immediately after its parent const validRows = [{ path: ['A'] }, { path: ['A', 'A'] }, { path: ['B'] }]; // ❌ The row A.A is not immediately after its parent const invalidRows = [{ path: ['A'] }, { path: ['B'] }, { path: ['A', 'A'] }];
Children lazy-loading
⚠️ This feature isn't implemented yet. It's coming.
👍 Upvote issue #3377 if you want to see it land faster.
Alternatively, you can achieve a similar behavior by implementing this feature outside the component as shown bellow. This implementation does not support every feature of the grid but can be a good starting point for large datasets.
The idea is to add a property descendantCount on the row and to use it instead of the internal grid state.
To do so, we need to override both the renderCell of the grouping column and to manually open the rows by listening to GridEvents.rowExpansionChange.
Master detail
The master detail feature allows expanding a row to display additional information inside a panel.
To use this feature, pass a function to the getDetailPanelContent prop with the content to be rendered inside the panel.
Any valid React element can be used as the row detail, even another grid.
The height of the detail panel content needs to be provided upfront.
The grid assumes the value of 500px by default however this can be configured by passing a function to the getDetailPanelHeight prop that returns the required height.
Both props are called with a GridRowParams object, allowing you to return a different value for each row.
<DataGridPro
getDetailPanelContent={({ row }) => <div>Row ID: {row.id}</div>}
getDetailPanelHeight={({ row }) => 100} // Optional, default is 500px.
/>
To expand a row click on the "i" icon, or press Ctrl+Enter inside one of the cells of the row.
Returning null or undefined as the value of getDetailPanelContent will prevent the respective row from being expanded.
⚠ Always memoize the function provided to
getDetailPanelContentandgetDetailPanelHeight. The grid depends on the referential value of these props to cache their values and optimize the rendering.const getDetailPanelContent = React.useCallback(() => { ... }, []); <DataGridPro getDetailPanelContent={getDetailPanelContent} />⚠ Depending on the height of the detail panel, you may see a blank space when scrolling. This is caused by the grid using a lazy approach to update the rendered rows. Set
rowThresholdto 0 to force new rows to be rendered more often to fill the blank space. Note that this may reduce the performance.<DataGridPro rowThreshold={0} />
Controlling expanded detail panels
To control which rows are expanded, pass a list of row IDs to the detailPanelExpandedRowIds prop.
Passing a callback to the onDetailPanelExpandedRowIds prop can be used to detect when a row gets expanded or collapsed.
On the other hand, if you only want to initialize the grid with some rows already expanded, use the initialState prop as follows:
<DataGridPro initialState={{ detailPanel: { expandedRowIds: [1, 2, 3] } }}>
Using a detail panel as a form
As an alternative to the built-in row editing, a form component can be rendered inside the detail panel, allowing the user to edit the current row values.
The following demo shows integration with react-hook-form, but other form libraries are also supported.
Customizing the detail panel toggle
To change the icon used for the toggle, you can provide a different component for the icon slot as follow:
<DataGridPro
components={{
DetailPanelExpandIcon: CustomExpandIcon,
DetailPanelCollapseIcon: CustomCollapseIcon,
}}
/>
If this is not sufficient, the entire toggle component can be overridden.
To fully customize it, add another column with field: GRID_DETAIL_PANEL_TOGGLE_FIELD to your set of columns.
The grid will detect that there is already a toggle column defined and it will not add another toggle in the default position.
The new toggle component can be provided via renderCell in the same as any other column.
By only setting the field, is up to you to configure the remaning options (e.g. disable the column menu, filtering, sorting).
To already start with a few suggested options configured, spread GRID_DETAIL_PANEL_TOGGLE_COL_DEF when defining the column.
<DataGridPro
columns={[
{
field: GRID_DETAIL_PANEL_TOGGLE_FIELD,
renderCell: (params) => <CustomDetailPanelToggle {...params}>
},
]}
/>
// or
<DataGridPro
columns={[
{
...GRID_DETAIL_PANEL_TOGGLE_COL_DEF, // Already contains the right field
renderCell: (params) => <CustomDetailPanelToggle {...params}>
},
]}
/>
This approach can also be used to change the location of the toggle column, as shown below.
Note: As any ordinary cell renderer, the
valueprop is also available and it corresponds to the state of the row:truewhen expanded andfalsewhen collapsed.
Disable detail panel content scroll
By default, the detail panel has a width that is the sum of the widths of all columns.
This means that when a horizontal scrollbar is present, scrolling it will also scroll the panel content.
To avoid this behavior, set the size of the detail panel to the outer size of the grid.
Use apiRef.current.getRootDimensions() to get the latest dimension values.
Finally, to prevent the panel from scrolling, set position: sticky and left: 0.
The following demo shows how this can be achieved. Notice that the toggle column is pinned to make sure that it will always be visible when the grid is scrolled horizontally.
getExpandedDetailPanels()
Returns the rows whose detail panel is open.
Signature:
getExpandedDetailPanels: () => GridRowId[]setExpandedDetailPanels()
Changes which rows to expand the detail panel.
Signature:
setExpandedDetailPanels: (ids: GridRowId[]) => voidtoggleDetailPanel()
Expands or collapses the detail panel of a row.
Signature:
toggleDetailPanel: (id: GridRowId) => void🚧 Aggregation
⚠️ This feature isn't implemented yet. It's coming.
👍 Upvote issue #213 if you want to see it land faster.
When grouping, you will be able to apply an aggregation function to populate the group row with values.
🚧 Pivoting
⚠️ This feature isn't implemented yet. It's coming.
👍 Upvote issue #214 if you want to see it land faster.
Pivoting will allow you to take a columns values and turn them into columns.