Migration from v7 to v8
This guide describes the changes needed to migrate the Data Grid from v7 to v8.
Introduction
This is a reference guide for upgrading @mui/x-data-grid from v7 to v8.
Start using the new release
In package.json, change the version of the Data Grid package to latest.
-"@mui/x-data-grid": "^7.x.x",
+"@mui/x-data-grid": "latest",
-"@mui/x-data-grid-pro": "^7.x.x",
+"@mui/x-data-grid-pro": "latest",
-"@mui/x-data-grid-premium": "^7.x.x",
+"@mui/x-data-grid-premium": "latest",
Since v8 is a major release, it contains changes that affect the public API.
These changes were done for consistency, improved stability and to make room for new features.
Described below are the steps needed to migrate from v7 to v8.
Package layout changes
MUI X v8 packages have been updated to use the Node.js exports field, following Material v7 package layout changes.
MUI X v8 packages are compatible with Material UI v7 out of the box. We encourage upgrading to Material UI v7 to take advantage of better ESM support.
Material UI v6 and v5 can still be used but require some additional steps if you are importing the packages in a Node.js environment. Follow the instructions in the Usage with Material UI v5/v6 guide.
Modern bundles have also been removed, as the potential for a smaller bundle size is no longer significant. If you've configured aliases for these bundles, you must remove them now.
{
resolve: {
alias: {
- '@mui/x-data-grid': '@mui/x-data-grid/modern',
- '@mui/x-data-grid-pro': '@mui/x-data-grid-pro/modern',
- '@mui/x-data-grid-premium': '@mui/x-data-grid-premium/modern',
},
},
}
Run codemods
The preset-safe codemod will automatically adjust the bulk of your code to account for breaking changes in v8. You can run v8.0.0/data-grid/preset-safe targeting only Data Grid or v8.0.0/preset-safe to target the other packages as well.
You can either run it on a specific file, folder, or your entire codebase when choosing the <path> argument.
# Data Grid specific
npx @mui/x-codemod@latest v8.0.0/data-grid/preset-safe <path>
# Target the other packages as well
npx @mui/x-codemod@latest v8.0.0/preset-safe <path>
Breaking changes that are handled by this codemod are prefixed with a ✅ emoji.
If you have already applied the v8.0.0/data-grid/preset-safe (or v8.0.0/preset-safe) codemod, then you should not need to take any further action on these items.
All other changes must be handled manually.
Breaking changes
Since v8 is a major release, it contains some changes that affect the public API. These changes were done for consistency, improve stability and make room for new features. Below are described the steps you need to make to migrate from v7 to v8.
✅ Setting license key
The deprecated LicenseInfo export was removed from the @mui/x-data-grid-pro and @mui/x-data-grid-premium packages.
You have to import it from @mui/x-license instead:
-import { LicenseInfo } from '@mui/x-data-grid-pro';
-import { LicenseInfo } from '@mui/x-data-grid-premium';
+import { LicenseInfo } from '@mui/x-license';
LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY');
Props
- Passing additional props (like
data-*,aria-*) directly on the Data Grid component is no longer supported. To pass the props, useslotProps:- For the
.rootelement, useslotProps.root - For the
.mainelement (the one withrole="grid"), useslotProps.main
- For the
Selection
The default value of the
rowSelectionPropagationprop has been changed to{ parents: true, descendants: true }which means that the selection will be propagated to the parents and descendants by default. To revert to the previous behavior, passrowSelectionPropagation={{ parents: false, descendants: false }}.✅ The prop
indeterminateCheckboxActionhas been removed. Clicking on an indeterminate checkbox "selects" the unselected descendants. This is the reverse of the previous Unselect all behavior, where clicking on an indeterminate checkbox would deselect the selected descendants.The "Select all" checkbox would now be checked when all the selectable rows are selected, ignoring rows that are not selectable because of the
isRowSelectableprop.✅ The row selection model has been changed from
GridRowId[]to{ type: 'include' | 'exclude'; ids: Set<GridRowId> }. UsingSetallows for a more efficient row selection management. Theexcludeselection type allows to select all rows except the ones in theidsset.This change impacts the following props:
rowSelectionModelonRowSelectionModelChange
-const [rowSelectionModel, setRowSelectionModel] = React.useState<GridRowSelectionModel>([]); +const [rowSelectionModel, setRowSelectionModel] = React.useState<GridRowSelectionModel>({ + type: 'include', + ids: new Set(), +});This change also impacts the
gridRowSelectionStateSelectorselector. For convenience, use thegridRowSelectionManagerSelectorselector to handle both selection types:-const rowSelection = gridRowSelectionStateSelector(apiRef); -const isRowSelected = rowSelection.includes(rowId); +const rowSelectionManager = gridRowSelectionManagerSelector(apiRef); +const isRowSelected = rowSelectionManager.has(rowId);There is also a
createRowSelectionManagerutility function that can be used to manage the row selection:const rowSelectionManager = createRowSelectionManager({ type: 'include', ids: new Set(), }); rowSelectionManager.select(rowId); rowSelectionManager.unselect(rowId); rowSelectionManager.has(rowId);The
selectedIdsLookupSelectorselector has been removed. Use thegridRowSelectionManagerSelectororgridRowSelectionStateSelectorselectors instead.✅ The
selectedGridRowsSelectorhas been renamed togridRowSelectionIdsSelector.✅ The
selectedGridRowsCountSelectorhas been renamed togridRowSelectionCountSelector.
Changes to the public API
✅ The
rowPositionsDebounceMsprop was removed.✅ The
resetPageOnSortFilterprop was removed. The Data Grid now goes back to the first page after sort or filter is applied.The
apiRef.current.resize()method was removed.The
apiRef.current.forceUpdate()method was removed. Use selectors combined withuseGridSelector()hook to react to changes in the state.The
<GridOverlays />component is not exported anymore.The
<GridSaveAltIcon />icon is not exported anymore. ImportSaveAltfrom@mui/icons-materialinstead.The
sanitizeFilterItemValue()utility is not exported anymore.gridRowsDataRowIdToIdLookupSelectorwas removed. UsegridRowsLookupSelectorin combination withgridRowIdSelectormethod instead.-const idToIdLookup = gridRowsDataRowIdToIdLookupSelector(apiRef); -const rowId = idToIdLookup[id]; +const rowsLookup = gridRowsLookupSelector(apiRef); +const rowId = gridRowIdSelector(apiRef, rowsLookup[id]);✅ The feature row spanning is now stable.
<DataGrid - unstable_rowSpanning + rowSpanning />✅ The data source feature and its related props are now stable.
<DataGridPro - unstable_dataSource={dataSource} - unstable_dataSourceCache={cache} - unstable_lazyLoading - unstable_lazyLoadingRequestThrottleMs={100} - unstable_onDataSourceError={() => {}} + dataSource={dataSource} + dataSourceCache={cache} + lazyLoading + lazyLoadingRequestThrottleMs={100} + onDataSourceError={() => {}} />The data source API is now stable.
-apiRef.current.unstable_dataSource.getRows(); +apiRef.current.dataSource.getRows();The list view feature and its related props are now stable.
✅ The
unstable_listViewprop has been renamed tolistView.✅ The
unstable_listColumnprop has been renamed tolistViewColumn.The
GridListColDeftype has been renamed toGridListViewColDef.-const listViewColDef: GridListColDef = { +const listViewColDef: GridListViewColDef = { field: 'listColumn', renderCell: ListViewCell, }; <DataGridPro - unstable_listView - unstable_listColumn={listViewColDef} + listView + listViewColumn={listViewColDef} />Return type of the
useGridApiRef()hook and the type ofapiRefprop are updated to explicitly include the possibilty ofnull. In addition to this,useGridApiRef()returns a reference that is initialized withnullinstead of{}.Only the initial value and the type are updated. Logic that initializes the API and its availability remained the same, which means that if you could access API in a particular line of your code before, you are able to access it as well after this change.
Depending on the context in which the API is being used, you can decide what is the best way to deal with
nullvalue. Some options are:- Use optional chaining
- Use non-null assertion operator if you are sure your code is always executed when the
apiRefis notnull - Return early if
apiRefisnull - Throw an error if
apiRefisnull
GridSortIteminterface is not exported anymore.createUseGridApiEventHandler()is not exported anymore.✅ The
showToolbarprop is now required to display the toolbar.It is no longer necessary to pass
GridToolbaras a slot to display the default toolbar.<DataGrid + showToolbar - slots={{ - toolbar: GridToolbar, - }} />The quick filter is now shown in the toolbar by default. Use
slotProps={{ toolbar: { showQuickFilter: false } }}to hide it.The signature of
onDataSourceError()has been updated to support future use-cases.<DataGrid - onDataSourceError={(error: Error, params: GridGetRowsParams) => { - if (params.filterModel) { - // do something - } - }} + onDataSourceError={(error: GridGetRowsError | GridUpdateRowError) => { + if (error instanceof GridGetRowsError && error.params.filterModel) { + // do something + } + }} />The
useGridApiEventHandler()hook has been renamed touseGridEvent().The
useGridApiOptionHandler()hook has been renamed touseGridEventPriority().
Behavioral changes
The "Reset" button in the column visibility panel now resets to the initial column visibility model instead of the model when the panel was opened. The reset behavior follows these rules:
- If an initial
columnVisibilityModelis provided, it resets to that model. - If a controlled
columnVisibilityModelis provided, it resets to the first model value. - When the columns are updated (via the
columnsprop orupdateColumns()API method), the reset reference point updates to the currentcolumnVisibilityModel.
To revert to the previous behavior, provide a custom component to the
slots.columnsManagement.- If an initial
The density selector has been removed from the toolbar. It is still possible to set the density programmatically via the
densityprop. A density selector can be added to a custom toolbar passed toslots.toolbar. See Toolbar component—Settings menu for an example.
Localization
- If
estimatedRowCountis used, the text provided to the Table Pagination component from the Material UI library is updated and requires additional translations. Check the example at the end of Index-based pagination section.
Accessibility
- The Grid is more aligned with the WAI-ARIA authoring practices and sets the
roleattribute totreegridif the Data Grid is used with row grouping feature.
State
The selectors signature has been updated. They are only accepting
apiRefas a first argument. Some selectors support additional arguments.-mySelector(state, instanceId); +mySelector(apiRef);or
-mySelector(state, instanceId); +mySelector(apiRef, arguments);The
useGridSelector()signature has been updated due to the introduction of arguments parameter in the selectors. Passundefinedasargumentsif the selector doesn't use any arguments.-const output = useGridSelector(apiRef, selector, equals); +const output = useGridSelector(apiRef, selector, arguments, equals);The
filteredRowsLookupobject of the filter state does not containtruevalues anymore. If the row is filtered out, the value isfalse. Otherwise, the row id is not present in the object. This change only impacts you if you relied onfilteredRowsLookupto get ids of filtered rows. In this case,usegridDataRowIdsSelectorselector to get row ids and checkfilteredRowsLookupforfalsevalues:const filteredRowsLookup = gridFilteredRowsLookupSelector(apiRef); -const filteredRowIds = Object.keys(filteredRowsLookup).filter( - (rowId) => filteredRowsLookup[rowId] === true, -); +const rowIds = gridDataRowIdsSelector(apiRef); +const filteredRowIds = rowIds.filter((rowId) => filteredRowsLookup[rowId] !== false);The
visibleRowsLookupstate does not containtruevalues anymore. If the row is not visible, the value isfalse. Otherwise, the row id is not present in the object:const visibleRowsLookup = gridVisibleRowsLookupSelector(apiRef); -const isRowVisible = visibleRowsLookup[rowId] === true; +const isRowVisible = visibleRowsLookup[rowId] !== false;
Other exports
- ✅
ariaV8experimental flag is removed. It's now the default behavior. - Subcomponents that are in a React Portal must now be wrapped with
GridPortalWrapper
Filtering
- The clear button in header filter cells has moved to the header filter menu. Use
slotProps={{ headerFilterCell: { showClearIcon: true } }}to restore the clear button in the cell. - Custom filter input components typings have been modified.
CSS classes and styling
The Data Grid now has a default background color, and its customization has moved from
theme.mixins.MuiDataGridtotheme.palette.DataGridwith the following properties:bg: Sets the background color of the entire grid (new property)headerBg: Sets the background color of the header (previously namedcontainerBackground)pinnedBg: Sets the background color of pinned rows and columns (previously namedpinnedBackground)
const theme = createTheme({ - mixins: { - MuiDataGrid: { - containerBackground: '#f8fafc', - pinnedBackground: '#f1f5f9', - }, - }, + palette: { + DataGrid: { + bg: '#f8fafc', + headerBg: '#e2e8f0', + pinnedBg: '#f1f5f9', + }, + }, });The
detailPanels,pinnedColumns, andpinnedRowsRenderZoneclasses have been removed.The
main--hasSkeletonLoadingOverlayclass has been renamed tomain--hiddenContentand is now also applied when the "No columns" overlay is displayed.
Slots
- The
base*slots have a new set of typings. - The
baseFormControlslot was removed. - The
baseInputLabelslot was removed. - The
baseInputAdornmentslot was removed. - The
paginationslot has been mostly refactored tobasePagination. - The
paperslot has been renamed topanelContent. - The
columnUnsortedIconslot was removed. - The icon slots now require material icons to be passed like
Icon as any. Note: This is due to typing issues that might be resolved later.
Bundling
The Data Grid now requires a bundler that can handle CSS imports. See Quickstart-Bundling for more details.