Upgrade to v10
This guide explains how to upgrade from Material UI v9 to v10.
Breaking changes
Since v10 is a new major release, it contains some changes that affect the public API. The steps you need to take to migrate from Material UI v9 to v10 are described below.
Khmer locale renamed
The Khmer locale is now exported as kmKH instead of khKH, to match the ISO 639-1 code for Khmer (km).
-import { khKH } from '@mui/material/locale';
+import { kmKH } from '@mui/material/locale';
-const theme = createTheme(themeOptions, khKH);
+const theme = createTheme(themeOptions, kmKH);
Numbers in TablePagination are now formatted with the km-KH locale.
Previously, Intl.NumberFormat didn't recognize kh-KH and fell back to the runtime's default locale.
Spacing uses CSS gap
Stack, DialogActions, CardActions and AccordionActions now space their children with the CSS gap property instead of a margin on each child after the first.
Stack
The useFlexGap prop has been removed.
Remove it from your Stack components and from the theme's default props:
-<Stack spacing={2} useFlexGap>
+<Stack spacing={2}>
If you didn't use useFlexGap, check your layouts for these differences:
Children's own margins now add to the
spacing. Previously, Stack reset them to0. To reset them again:<Stack spacing={2} sx={{ '& > :not(style):not(style)': { m: 0 } }}>spacingalso applies between lines when the children wrap.Negative
spacingvalues and'auto'are no longer supported. Removespacingand apply margins to the children instead. For example, to preserve overlapping children in a row:-<Stack direction="row" spacing={-1}> +<Stack + direction="row" + sx={{ '& > :not(style) ~ :not(style)': { ml: -1 } }} +>Put the margin on the side that faces the previous child:
mlforrow,mrforrow-reverse,mtforcolumn, andmbforcolumn-reverse. Use the value'auto'to preservespacing="auto".Percentage spacing is now relative to the container's width for horizontal gaps and height for vertical gaps. Previously, percentage margins used the container's width in both directions. For example,
spacing="10%"now produces no gap in a column whose height is determined by its children. Use a numeric spacing value or a length such as'1rem'for spacing that does not depend on the container's dimensions.
DialogActions, CardActions and AccordionActions
If you customized the space between the actions, through the spacing style override or a margin on the actions, set gap on the root instead.
SpeedDial generated ids
SpeedDial no longer derives the ids of its actions container and actions from ariaLabel.
The ids are now based on the id prop, or on a generated unique id when it is omitted.
This avoids duplicate ids when several speed dials share the same ariaLabel.
If you target these ids in CSS or tests, pass an explicit id:
-<SpeedDial ariaLabel="Actions" />
+<SpeedDial ariaLabel="Actions" id="Actions" />
The ids are then Actions-actions for the actions container and Actions-action-0, Actions-action-1, and so on for each action.
CSS layers are always on
Material UI puts its styles in the mui cascade layer, split into sub-layers: mui.global, mui.components, mui.theme, mui.custom and mui.sx.
This can't be turned off: cssLayers: false is ignored and logs an error in development.
This changes which styles win:
- CSS that isn't in a layer, such as a reset or your own stylesheets, now overrides Material UI's styles whatever its specificity.
Put resets in a layer that comes before
mui, and declare the order with themodularCssLayerstheme option, for examplemodularCssLayers: '@layer reset, mui;'. - Theme
styleOverridesandvariants,styled()and thesxprop now override the components' state styles, such as:hover,.Mui-disabledand.Mui-selected, even when they're less specific.
These are the patterns that most often need a change:
A style that should only apply in the default state. Exclude the states, or set their values too:
<FormLabel sx={{ - color: 'text.primary', + '&:not(.Mui-focused, .Mui-error, .Mui-disabled)': { + color: 'text.primary', + }, }} />MuiIconButton: { styleOverrides: { root: ({ theme }) => ({ color: theme.palette.text.primary, + [`&.${iconButtonClasses.disabled}`]: { + color: theme.palette.action.disabled, + }, }), }, },An override that undoes a component's more specific rule. For example, an
inputoverride ofMuiOutlinedInputwithpadding: 0now also removes the room that the Select leaves for its icon. Set the value back for that case:MuiOutlinedInput: { styleOverrides: { input: { padding: 0, + [`&.${selectClasses.select}`]: { + paddingRight: 32, + }, }, }, },An
sxvalue that the component sets for some breakpoints. Thesxprop now wins at every breakpoint, so<Grid size={{ md: 7 }} sx={{ width: '100%' }}>is full width on large screens too. Use the component's own prop instead:<Grid size={{ xs: 12, md: 7 }}>.A component's styles for its children. Rules such as the padding that an
Autocompletesets on its input, or the inner corners of aButtonGroup, are inmui.components, so the children's own theme overrides,styled()andsxnow win over them. For example, aMuiOutlinedInputroot override withpadding: '8px 12px'now also replaces the room that the Autocomplete leaves for its buttons. Drop the conflicting value from the child's styles, or set it back for that case.GlobalStylesthat target Material UI components.GlobalStylesgo inmui.global, the lowest sub-layer, so they no longer override the components' styles. Move these rules to the theme'sstyleOverrides, tosxorstyled(), or to a stylesheet outside the layers.
To keep the v9 precedence between Material UI's own styles, put them all in the mui layer, without sub-layers:
const theme = createTheme({
cssLayers: 'single',
});
This matches v9's enableCssLayer: mui goes where your CSS declares it, for example @layer theme, base, mui, components, utilities;.
modularCssLayers: false now does the same as cssLayers: 'single', and modularCssLayers: true can be removed, since sub-layers are the default.