Migration from v4 to v5
Yeah, v5 has been released!
Looking for the v4 docs? Find them here.
This document is a work in progress. Have you upgraded your site and run into something that's not covered here? Add your changes on GitHub.
Introduction
This is a reference for upgrading your site from Material-UI v4 to v5. While there's a lot covered here, you probably won't need to do everything for your site. We'll do our best to keep things easy to follow, and as sequential as possible so you can quickly get rocking on v5!
Why you should migrate
This documentation page covers the how of migrating from v4 to v5. The why is covered in the release blog post on Medium.
Updating your dependencies
The very first thing you will need to do is to update your dependencies.
Update Material-UI version
You need to update your package.json
to use the latest version of Material-UI and its peer dependencies.
"dependencies": {
"@emotion/react": "^11.0.0",
"@emotion/styled": "^11.0.0",
"@material-ui/core": "^5.0.0"
}
Or run
npm install @material-ui/core@next @emotion/react @emotion/styled
or
yarn add @material-ui/core@next @emotion/react @emotion/styled
Handling breaking changes
Supported browsers and node versions
The targets of the default bundle have changed.
The exact versions will be pinned on release from the browserslist query "> 0.5%, last 2 versions, Firefox ESR, not dead, not IE 11, maintained node versions"
.
The default bundle now supports:
- Node 12 (up from 8)
- Chrome 84 (up from 49)
- Edge 85 (up from 14)
- Firefox 78 (up from 52)
- Safari 13 (macOS) and 12.2 (iOS) (up from 10)
- and more (see .browserslistrc (
stable
entry))
It no longer supports IE 11. If you need to support IE 11, check out our legacy bundle.
non-ref-forwarding class components
Support for non-ref-forwarding class components in the component
prop or as immediate children
has been dropped. If you were using unstable_createStrictModeTheme
or didn't see any warnings related to findDOMNode
in React.StrictMode
then you don't need to do anything.
Otherwise check out the "Caveat with refs" section in our composition guide to find out how to migrate.
This change affects almost all components where you're using the component
prop or passing children
to components that require children
to be elements (e.g. <MenuList><CustomMenuItem /></MenuList>
)
Supported React version
The minimum supported version of React was increased from v16.8.0 to v17.0.0.
Supported TypeScript version
The minimum supported version of TypeScript was increased from v3.2 to v3.5.
We try to align with types released from DefinitelyTyped (i.e. packages published on npm under the @types
namespace).
We will not change the minimum supported version in a major version of Material-UI.
However, we generally recommend to not use a TypeScript version older than the lowest supported version of DefinitelyTyped
Styled engine
The styled engine used in v5 by default is emotion
. While migrating from JSS to emotion, if you are using JSS style overrides for your components (for example overrides created by makeStyles
), you need to take care of the CSS injection order. In order to do this, you need to have on the top of your application the StylesProvider
with the injectFirst
option. Here is an example of it:
import * as React from 'react';
import { StyledEngineProvider } from '@material-ui/core/styles';
export default function GlobalCssPriority() {
return (
<StyledEngineProvider injectFirst>
{/* Your component tree. Now you can override Material-UI's styles. */}
</StyledEngineProvider>
);
}
Note: If you are using emotion and have a custom cache in your app, that one will override the one coming from Material-UI. In order for the injection order to still be correct, you need to add the prepend option. Here is an example:
import * as React from 'react';
import { CacheProvider } from '@emotion/react';
import createCache from '@emotion/cache';
const cache = createCache({
key: 'css',
prepend: true,
});
export default function PlainCssPriority() {
return (
<CacheProvider value={cache}>
{/* Your component tree. Now you can override Material-UI's styles. */}
</CacheProvider>
);
}
Note: If you are using styled-components and have StyleSheetManager
with a custom target
, make sure that the target is the first element in the HTML <head>
. If you are curious to see how it can be done, you can take a look on the StylesProvider
implementation in the @material-ui/styled-engine-sc
package.
Theme
The function
createMuiTheme
was renamed tocreateTheme
to make more intuitive to use withThemeProvider
.-import { createMuiTheme } from '@material-ui/core/styles'; +import { createTheme } from '@material-ui/core/styles'; -const theme = createMuiTheme({ +const theme = createTheme({
The default background color is now
#fff
in light mode and#121212
in dark mode. This matches the material design guidelines.Breakpoints are now treated as values instead of ranges. The behavior of
down(key)
was changed to define media query less than the value defined with the corresponding breakpoint (exclusive). Thebetween(start, end)
was also updated to define media query for the values between the actual values of start (inclusive) and end (exclusive). When using thedown()
breakpoints utility you need to update the breakpoint key by one step up. When using thebetween(start, end)
the end breakpoint should also be updated by one step up. The same should be done when using theHidden
component. Find examples of the changes required defined below:-theme.breakpoints.down('sm') // '@media (max-width:959.95px)' - [0, sm + 1) => [0, md) +theme.breakpoints.down('md') // '@media (max-width:959.95px)' - [0, md)
-theme.breakpoints.between('sm', 'md') // '@media (min-width:600px) and (max-width:1279.95px)' - [sm, md + 1) => [0, lg) +theme.breakpoints.between('sm', 'lg') // '@media (min-width:600px) and (max-width:1279.95px)' - [0, lg)
-theme.breakpoints.between('sm', 'xl') // '@media (min-width:600px)' +theme.breakpoints.up('sm') // '@media (min-width:600px)'
-<Hidden smDown>{...}</Hidden> // '@media (min-width:600px)' +<Hidden mdDown>{...}</Hidden> // '@media (min-width:600px)'
The
theme.breakpoints.width
utility was removed because it's redundant. Usetheme.breakpoints.values
to get the same values.-theme.breakpoints.width('md') +theme.breakpoints.values.md
The signature of
theme.palette.augmentColor
helper has changed:-theme.palette.augmentColor(red); +theme.palette.augmentColor({ color: red, name: 'brand' });
The
theme.typography.round
helper was removed because it was no longer used. If you need it, use the function below:function round(value) { return Math.round(value * 1e5) / 1e5; }
Upgrade helper
For a smoother transition, the adaptV4Theme
helper allows you to iteratively upgrade some of the theme changes to the new theme structure.
-import { createMuiTheme } from '@material-ui/core/styles';
+import { createTheme, adaptV4Theme } from '@material-ui/core/styles';
-const theme = createMuiTheme({
+const theme = createTheme(adaptV4Theme({
// v4 theme
-});
+}));
The following changes are supported by the adapter.
Changes
The "gutters" abstraction hasn't proven to be used frequently enough to be valuable.
-theme.mixins.gutters(), +paddingLeft: theme.spacing(2), +paddingRight: theme.spacing(2), +[theme.breakpoints.up('sm')]: { + paddingLeft: theme.spacing(3), + paddingRight: theme.spacing(3), +},
theme.spacing
now returns single values with px units by default. This change improves the integration with styled-components & emotion.Before:
theme.spacing(2) => 16
After:
theme.spacing(2) => '16px'
The
theme.palette.type
key was renamed totheme.palette.mode
, to better follow the "dark mode" term that is usually used for describing this feature.import { createTheme } from '@material-ui/core/styles'; -const theme = createTheme({palette: { type: 'dark' }}), +const theme = createTheme({palette: { mode: 'dark' }}),
The
theme.palette.text.hint
key was unused in Material-UI components, and has been removed. If you depend on it, you can add it back:import { createTheme } from '@material-ui/core/styles'; -const theme = createTheme(), +const theme = createTheme({ + palette: { text: { hint: 'rgba(0, 0, 0, 0.38)' } }, +});
The components' definitions inside the theme were restructured under the
components
key, to allow people easier discoverability about the definitions regarding one component.
props
import { createTheme } from '@material-ui/core/styles';
const theme = createTheme({
- props: {
- MuiButton: {
- disableRipple: true,
- },
- },
+ components: {
+ MuiButton: {
+ defaultProps: {
+ disableRipple: true,
+ },
+ },
+ },
});
overrides
import { createTheme } from '@material-ui/core/styles';
const theme = createTheme({
- overrides: {
- MuiButton: {
- root: { padding: 0 },
- },
- },
+ components: {
+ MuiButton: {
+ styleOverrides: {
+ root: { padding: 0 },
+ },
+ },
+ },
});
Styles
- Renamed
fade
toalpha
to better describe its functionality. The previous name was leading to confusion when the input color already had an alpha value. The helper overrides the alpha value of the color.
- import { fade } from '@material-ui/core/styles';
+ import { alpha } from '@material-ui/core/styles';
const classes = makeStyles(theme => ({
- backgroundColor: fade(theme.palette.primary.main, theme.palette.action.selectedOpacity),
+ backgroundColor: alpha(theme.palette.primary.main, theme.palette.action.selectedOpacity),
}));
-The createStyles
function from @material-ui/core/styles
was moved to the one exported from @material-ui/styles
. It is necessary for removing the dependency to @material-ui/styles
in the core package.
-import { createStyles } from '@material-ui/core/styles';
+import { createStyles } from '@material-ui/styles';
System
The following system functions (and properties) were renamed because they are considered deprecated CSS:
gridGap
togap
gridRowGap
torowGap
gridColumnGap
tocolumnGap
Use spacing unit in
gap
,rowGap
, andcolumnGap
. If you were using a number previously, you need to mention the px to bypass the new transformation withtheme.spacing
.<Box - gap={2} + gap="2px" >
Replace
css
prop withsx
to avoid collision with styled-components & emotion CSS props.
-<Box css={{ color: 'primary.main' }} />
+<Box sx={{ color: 'primary.main' }} />
Core components
As the core components use emotion as a styled engine, the props used by emotion are not intercepted. The prop as
in the following codesnippet will not be propagated to the SomeOtherComponent
.
<MuiComponent component={SomeOtherComponent} as="button" />
AppBar
- [AppBar] Remove z-index when position static and relative
Alert
Move the component from the lab to the core. The component is now stable.
-import Alert from '@material-ui/lab/Alert'; -import AlertTitle from '@material-ui/lab/AlertTitle'; +import Alert from '@material-ui/core/Alert'; +import AlertTitle from '@material-ui/core/AlertTitle';
You can use the
moved-lab-modules
codemod for automatic migration.
Autocomplete
Move the component from the lab to the core. The component is now stable.
-import Autocomplete from '@material-ui/lab/Autocomplete'; -import useAutocomplete from '@material-ui/lab/useAutocomplete'; +import Autocomplete from '@material-ui/core/Autocomplete'; +import useAutoComplete from '@material-ui/core/useAutocomplete';
You can use our
moved-lab-modules
codemod for automatic migration.Remove
debug
prop. There are a couple of simpler alternatives:open={true}
, Chrome devtools "Emulate focused", or React devtools prop setter.renderOption
should now return the full DOM structure of the option. It makes customizations easier. You can recover from the change with:<Autocomplete - renderOption={(option, { selected }) => ( - <React.Fragment> + renderOption={(props, option, { selected }) => ( + <li {...props}> <Checkbox icon={icon} checkedIcon={checkedIcon} style={{ marginRight: 8 }} checked={selected} /> {option.title} - </React.Fragment> + </li> )} />
Rename
closeIcon
prop withclearIcon
to avoid confusion.-<Autocomplete closeIcon={defaultClearIcon} /> +<Autocomplete clearIcon={defaultClearIcon} />
The following values of the reason argument in
onChange
andonClose
were renamed for consistency:create-option
tocreateOption
select-option
toselectOption
remove-option
toremoveOption
Change the CSS rules that use
[data-focus="true"]
to use.Mui-focused
. Thedata-focus
attribute is not set on the focused option anymore, instead, global class names are used.-'.MuiAutocomplete-option[data-focus="true"]': { +'.MuiAutocomplete-option.Mui-focused': {
Rename
getOptionSelected
toisOptionEqualToValue
to better describe its purpose.<Autocomplete - getOptionSelected={(option, value) => option.title === value.title} + isOptionEqualToValue={(option, value) => option.title === value.title}
Avatar
Rename
circle
tocircular
for consistency. The possible values should be adjectives, not nouns:-<Avatar variant="circle"> -<Avatar classes={{ circle: 'className' }}> +<Avatar variant="circular"> +<Avatar classes={{ circular: 'className' }}>
Move the AvatarGroup from the lab to the core.
-import AvatarGroup from '@material-ui/lab/AvatarGroup'; +import AvatarGroup from '@material-ui/core/AvatarGroup';
Badge
Rename
circle
tocircular
andrectangle
torectangular
for consistency. The possible values should be adjectives, not nouns:-<Badge overlap="circle"> -<Badge overlap="rectangle"> +<Badge overlap="circular"> +<Badge overlap="rectangular"> <Badge classes={{ - anchorOriginTopRightRectangle: 'className' - anchorOriginBottomRightRectangle: 'className' - anchorOriginTopLeftRectangle: 'className' - anchorOriginBottomLeftRectangle: 'className' - anchorOriginTopRightCircle: 'className' - anchorOriginBottomRightCircle: 'className' - anchorOriginTopLeftCircle: 'className' + anchorOriginTopRightRectangular: 'className' + anchorOriginBottomRightRectangular: 'className' + anchorOriginTopLeftRectangular: 'className' + anchorOriginBottomLeftRectangular: 'className' + anchorOriginTopRightCircular: 'className' + anchorOriginBottomRightCircular: 'className' + anchorOriginTopLeftCircular: 'className' }}>
BottomNavigation
TypeScript: The
event
inonChange
is no longer typed as aReact.ChangeEvent
butReact.SyntheticEvent
.-<BottomNavigation onChange={(event: React.ChangeEvent<{}>) => {}} /> +<BottomNavigation onChange={(event: React.SyntheticEvent) => {}} />
Box
The system props have been deprecated in v5, and replaced with the
sx
prop.-<Box border="1px dashed grey" p={[2, 3, 4]} m={2}> +<Box sx={{ border: "1px dashed grey", p: [2, 3, 4], m: 2 }}>
This codemod will automatically update your code to the new syntax. You can read this section for the why behind the change of API.
The
borderRadius
system prop value transformation has been changed. If it receives a number, it multiplies this value with thetheme.shape.borderRadius
value. Use a string to provide an explicit value, inpx
.-<Box sx={{ borderRadius: 'borderRadius' }}> +<Box sx={{ borderRadius: 1 }}>
-<Box sx={{ borderRadius: 16 }}> +<Box sx={{ borderRadius: '16px' }}>
The following properties were renamed, because they are considered deprecated CSS proeprties:
gridGap
togap
gridColumnGap
tocolumnGap
gridRowGap
torowGap
-<Box gridGap="10px">
+<Box sx={{ gap: '10px' }}>
-<Box gridColumnGap="10px" gridRowGap="20px">
+<Box sx={{ columnGap: '10px', rowGap: '20px' }}>
The
clone
prop was removed because its behavior can be obtained by applying thesx
prop directly to the child if it is a Material-UI component.-<Box sx={{ border: '1px dashed grey' }} clone> - <Button>Save</Button> -</Box> +<Button sx={{ border: '1px dashed grey' }}>Save</Button>
The ability to pass a render prop was removed because its behavior can be obtained by applying the
sx
prop directly to the child if it is a Material-UI component.-<Box sx={{ border: '1px dashed grey' }}> - {(props) => <Button {...props}>Save</Button>} -</Box> +<Button sx={{ border: '1px dashed grey' }}>Save</Button>
For non-Material-UI components, use the
component
prop.-<Box sx={{ border: '1px dashed grey' }}> - {(props) => <button {...props}>Save</button>} -</Box> +<Box component="button" sx={{ border: '1px dashed grey' }}>Save</Box>
Button
The button
color
prop is now "primary" by default, and "default" has been removed. This makes the button closer to the Material Design specification and simplifies the API.-<Button color="primary" /> -<Button color="default" /> +<Button /> +<Button />
ButtonBase
- Remove the deprecated
buttonRef
prop. Theref
prop should be used in place.
Checkbox
Remove the second argument from
onChange
. You can pull out the checked state by accessingevent.target.checked
.function MyCheckbox() { - const handleChange = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => { + const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { + const checked = event.target.checked; }; return <Checkbox onChange={handleChange} />; }
The checkbox color prop is now "primary" by default. To continue using the "secondary" color, you must explicitly indicate
secondary
. This brings the checkbox closer to the Material Design specification.- <Checkbox /> + <Checkbox color="secondary />
Chip
- Rename
default
variant tofilled
for consistency.-<Chip variant="default"> +<Chip variant="filled">
CircularProgress
The
static
variant has been merged into thedeterminate
variant, with the latter assuming the appearance of the former. The removed variant was rarely useful. It was an exception to Material Design, and was removed from the specification.-<CircularProgress variant="determinate" />
-<CircularProgress variant="static" classes={{ static: 'className' }} /> +<CircularProgress variant="determinate" classes={{ determinate: 'className' }} />
NB: If you had previously customized determinate, your customizations are probably no longer valid. Please remove them.
Collapse
The
collapsedHeight
prop was renamedcollapsedSize
to support the horizontal direction.-<Collapse collapsedHeight={40}> +<Collapse collapsedSize={40}>
The
classes.container
key was changed to match the convention of the other components.-<Collapse classes={{ container: 'collapse' }}> +<Collapse classes={{ root: 'collapse' }}>
CssBaseline
The component was migrated to use the
@material-ui/styled-engine
(emotion
orstyled-components
) instead ofjss
. You should remove the@global
key when defining the style overrides for it. You could also start using the CSS template syntax over the JavaScript object syntax.const theme = createTheme({ components: { MuiCssBaseline: { - styleOverrides: { - '@global': { - html: { - WebkitFontSmoothing: 'auto', - }, - }, - }, + styleOverrides: ` + html { + -webkit-font-smoothing: auto; + } + ` }, }, });
The
body
font size has changed fromtheme.typography.body2
(0.875rem
) totheme.typography.body1
(1rem
). To return to the previous size, you can override it in the theme:const theme = createTheme({ typography: { body1: { fontSize: '0.875rem', }, }, });
(Note that this will also affect use of the Typography component with the default
body1
variant).
Dialog
The onE* transition props were removed. Use TransitionProps instead.
<Dialog - onEnter={onEnter} - onEntered={onEntered}, - onEntering={onEntered}, - onExit={onEntered}, - onExited={onEntered}, - onExiting={onEntered} + TransitionProps={{ + onEnter, + onEntered, + onEntering, + onExit, + onExited, + onExiting, + }} />
Remove the
disableBackdropClick
prop because redundant. Ignore close events fromonClose
whenreason === 'backdropClick'
instead.<Dialog - disableBackdropClick - onClose={handleClose} + onClose={(event, reason) => { + if (reason !== 'backdropClick') { + onClose(event, reason); + } + }} />
[withMobileDialog] Remove this higher-order component. The hook API allows a simpler and more flexible solution:
-import withMobileDialog from '@material-ui/core/withMobileDialog'; +import { useTheme, useMediaQuery } from '@material-ui/core'; function ResponsiveDialog(props) { - const { fullScreen } = props; + const theme = useTheme(); + const fullScreen = useMediaQuery(theme.breakpoints.down('sm')); const [open, setOpen] = React.useState(false); // ... -export default withMobileDialog()(ResponsiveDialog); +export default ResponsiveDialog;
Divider
Use border instead of background color. It prevents inconsistent height on scaled screens. For people customizing the color of the border, the change requires changing the override CSS property:
.MuiDivider-root { - background-color: #f00; + border-color: #f00; }
ExpansionPanel
Rename the
ExpansionPanel
components toAccordion
to use a more common naming convention:-import ExpansionPanel from '@material-ui/core/ExpansionPanel'; -import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'; -import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'; -import ExpansionPanelActions from '@material-ui/core/ExpansionPanelActions'; +import Accordion from '@material-ui/core/Accordion'; +import AccordionSummary from '@material-ui/core/AccordionSummary'; +import AccordionDetails from '@material-ui/core/AccordionDetails'; +import AccordionActions from '@material-ui/core/AccordionActions'; -<ExpansionPanel> +<Accordion> - <ExpansionPanelSummary> + <AccordionSummary> <Typography>Location</Typography> <Typography>Select trip destination</Typography> - </ExpansionPanelSummary> + </AccordionSummary> - <ExpansionPanelDetails> + <AccordionDetails> <Chip label="Barbados" onDelete={() => {}} /> <Typography variant="caption">Select your destination of choice</Typography> - </ExpansionPanelDetails> + </AccordionDetails> <Divider /> - <ExpansionPanelActions> + <AccordionActions> <Button size="small">Cancel</Button> <Button size="small">Save</Button> - </ExpansionPanelActions> + </AccordionActions> -</ExpansionPanel> +</Accordion>
TypeScript: The
event
inonChange
is no longer typed as aReact.ChangeEvent
butReact.SyntheticEvent
.-<Accordion onChange={(event: React.ChangeEvent<{}>, expanded: boolean) => {}} /> +<Accordion onChange={(event: React.SyntheticEvent, expanded: boolean) => {}} />
Rename
focused
tofocusVisible
for consistency:<Accordion classes={{ - focused: 'custom-focus-visible-classname', + focusVisible: 'custom-focus-visible-classname', }} />
Remove
display: flex
from AccordionDetails as its too opinionated. Most developers expect a display block.Remove
IconButtonProps
prop from AccordionSummary. The component renders a<div>
element instead of an IconButton. The prop is no longer necessary.
Fab
Rename
round
tocircular
for consistency. The possible values should be adjectives, not nouns:-<Fab variant="round"> +<Fab variant="circular">
FormControl
Change the default variant from
standard
tooutlined
. Standard has been removed from the Material Design Guidelines.-<FormControl value="Standard" /> -<FormControl value="Outlined" variant="outlined" /> +<FormControl value="Standard" variant="standard" /> +<FormControl value="Outlined" />
This codemod will automatically update your code.
Grid
Rename
justify
prop withjustifyContent
to be aligned with the CSS property name.-<Grid justify="center"> +<Grid justifyContent="center">
The props:
alignItems
alignContent
andjustifyContent
and theirclasses
and style overrides keys were removed: "align-items-xs-center", "align-items-xs-flex-start", "align-items-xs-flex-end", "align-items-xs-baseline", "align-content-xs-center", "align-content-xs-flex-start", "align-content-xs-flex-end", "align-content-xs-space-between", "align-content-xs-space-around", "justify-content-xs-center", "justify-content-xs-flex-end", "justify-content-xs-space-between", "justify-content-xs-space-around" and "justify-content-xs-space-evenly". These props are now considered part of the system, not on theGrid
component itself. If you still wish to add overrides for them, you can use thetheme.components.MuiGrid.variants
options. For exampleconst theme = createTheme({ components: { MuiGrid: { - styleOverrides: { - "align-items-xs-flex-end": { - marginTop: '20px', - }, - }, + variants: { + props: { alignItems: "flex-end" }, + style: { + marginTop: '20px', + }, + }], }, }, });
GridList
Rename the
GridList
components toImageList
to align with the current Material Design naming.Rename the GridList
spacing
prop togap
to align with the CSS attribute.Rename the GridList
cellHeight
prop torowHeight
.Add the
variant
prop to GridList.Rename the GridListItemBar
actionPosition
prop toposition
. (Note also the related classname changes.)Use CSS object-fit. For IE11 support either use a polyfill such as https://www.npmjs.com/package/object-fit-images, or continue to use the v4 component.
-import GridList from '@material-ui/core/GridList'; -import GridListTile from '@material-ui/core/GridListTile'; -import GridListTileBar from '@material-ui/core/GridListTileBar'; +import ImageList from '@material-ui/core/ImageList'; +import ImageListItem from '@material-ui/core/ImageListItem'; +import ImageListItemBar from '@material-ui/core/ImageListItemBar'; -<GridList spacing={8} cellHeight={200}> - <GridListTile> +<ImageList gap={8} rowHeight={200}> + <ImageListItem> <img src="file.jpg" alt="Image title" /> - <GridListTileBar + <ImageListItemBar title="Title" subtitle="Subtitle" /> - </GridListTile> -</GridList> + </ImageListItem> +</ImageList>
Hidden
This component was removed because its functionality can be created with the
sx
prop or theuseMediaQuery
hook.Use the
sx
prop to replaceimplementation="css"
:-<Hidden implementation="css" xlUp><Paper /></Hidden> -<Hidden implementation="css" xlUp><button /></Hidden> +<Paper sx={{ display: { xl: 'none', xs: 'block' } }} /> +<Box component="button" sx={{ display: { xl: 'none', xs: 'block' } }} />
-<Hidden implementation="css" mdDown><Paper /></Hidden> -<Hidden implementation="css" mdDown><button /></Hidden> +<Paper sx={{ display: { xs: 'none', md: 'block' } }} /> +<Box component="button" sx={{ display: { xs: 'none', md: 'block' } }} />
Use the
useMediaQuery
hook to replaceimplementation="js"
:-<Hidden implementation="js" xlUp><Paper /></Hidden> +const hidden = useMediaQuery(theme => theme.breakpoints.up('xl')); +return hidden ? null : <Paper />;
Icon
The default value of
fontSize
was changed fromdefault
tomedium
for consistency. In the unlikey event that you were using the valuedefault
, the prop can be removed:-<Icon fontSize="default">icon-name</Icon> +<Icon>icon-name</Icon>
Menu
The onE* transition props were removed. Use TransitionProps instead.
<Menu - onEnter={onEnter} - onEntered={onEntered}, - onEntering={onEntered}, - onExit={onEntered}, - onExited={onEntered}, - onExiting={onEntered} + TransitionProps={{ + onEnter, + onEntered, + onEntering, + onExit, + onExited, + onExiting, + }} >
The
selectedMenu
variant will not vertically align the selected item with the anchor anymore.
Modal
Remove the
disableBackdropClick
prop because redundant. Ignore close events fromonClose
whenreason === 'backdropClick'
instead.<Modal - disableBackdropClick - onClose={handleClose} + onClose={(event, reason) => { + if (reason !== 'backdropClick') { + onClose(event, reason); + } + }} />
Remove the
onEscapeKeyDown
prop because redundant. UseonClose
withreason === "escapeKeyDown"
instead.<Modal - onEscapeKeyDown={handleEscapeKeyDown} + onClose={(event, reason) => { + if (reason === 'escapeKeyDown') { + handleEscapeKeyDown(event); + } + }} />
Remove
onRendered
prop. Depending on your use case either use a callback ref on the child element or an effect hook in the child component.
NativeSelect
Merge the
selectMenu
slot intoselect
. SlotselectMenu
was redundant. Theroot
slot is no longer applied to the select, but to the root.-<NativeSelect classes={{ root: 'class1', select: 'class2', selectMenu: 'class3' }} /> +<NativeSelect classes={{ select: 'class1 class2 class3' }} />
OutlinedInput
Remove the
labelWidth
prop. Thelabel
prop now fulfills the same purpose, using CSS layout instead of JavaScript measurement to render the gap in the outlined.-<OutlinedInput labelWidth={20} /> +<OutlinedInput label="First Name" />
Paper
Change the background opacity based on the elevation in dark mode. This change was done to follow the Material Design guidelines. You can revert it in the theme:
const theme = createTheme({ components: { MuiPaper: { + styleOverrides: { root: { backgroundImage: 'unset' } }, }, }, });
Pagination
Move the component from the lab to the core. The component is now stable.
-import Pagination from '@material-ui/lab/Pagination'; -import PaginationItem from '@material-ui/lab/PaginationItem'; -import { usePagination } from '@material-ui/lab/Pagination'; +import Pagination from '@material-ui/core/Pagination'; +import PaginationItem from '@material-ui/core/PaginationItem'; +import usePagination from '@material-ui/core/usePagination';
You can use our
moved-lab-modules
codemod for automatic migration.Rename
round
tocircular
for consistency. The possible values should be adjectives, not nouns:-<Pagination shape="round"> -<PaginationItem shape="round"> +<Pagination shape="circular"> +<PaginationItem shape="circular">
Popover
The onE* transition props were removed. Use TransitionProps instead.
<Popover - onEnter={onEnter} - onEntered={onEntered}, - onEntering={onEntered}, - onExit={onEntered}, - onExited={onEntered}, - onExiting={onEntered} + TransitionProps={{ + onEnter, + onEntered, + onEntering, + onExit, + onExited, + onExiting, + }} />
The
getContentAnchorEl
prop was removed to simplify the positioning logic.
Popper
Upgrade Popper.js from v1 to v2. This third-party library has introduced a lot of changes.
You can read their migration guide or the following summary:The CSS prefixes have changed:
popper: { zIndex: 1, - '&[x-placement*="bottom"] $arrow': { + '&[data-popper-placement*="bottom"] $arrow': {
Method names have changed.
-popperRef.current.scheduleUpdate() +popperRef.current.update()
-popperRef.current.update() +popperRef.current.forceUpdate()
Modifiers' API has changed a lot. There are too many changes to be covered here.
Portal
- Remove
onRendered
prop. Depending on your use case either use a callback ref on the child element or an effect hook in the child component.
Radio
The radio color prop is now "primary" by default. To continue using the "secondary" color, you must explicitly indicate
secondary
. This brings the radio closer to the Material Design specification.-<Radio /> +<Radio color="secondary />
Rating
Move the component from the lab to the core. The component is now stable.
-import Rating from '@material-ui/lab/Rating'; +import Rating from '@material-ui/core/Rating';
You can use our
moved-lab-modules
codemod for automatic migration.Change the default empty icon to improve accessibility. If you have a custom
icon
prop but noemptyIcon
prop, you can restore the previous behavior with:<Rating icon={customIcon} + emptyIcon={null} />
Rename
visuallyhidden
tovisuallyHidden
for consistency:<Rating classes={{ - visuallyhidden: 'custom-visually-hidden-classname', + visuallyHidden: 'custom-visually-hidden-classname', }} />
RootRef
This component was removed. You can get a reference to the underlying DOM node of our components via
ref
prop. The component relied onReactDOM.findDOMNode
which is deprecated inReact.StrictMode
.-<RootRef rootRef={ref}> - <Button /> -</RootRef> +<Button ref={ref} />
Select
Change the default variant from
standard
tooutlined
. Standard has been removed from the Material Design Guidelines. If you are composing the Select with a form control component, you only need to updateFormControl
, the select inherits the variant from its context.-<Select value="Standard" /> -<Select value="Outlined" variant="outlined" /> +<Select value="Standard" variant="standard" /> +<Select value="Outlined" />
This codemod will automatically update your code.
Remove the
labelWidth
prop. Thelabel
prop now fulfills the same purpose, using CSS layout instead of JavaScript measurement to render the gap in the outlined. The TextField already handles it by default.-<Select variant="outlined" labelWidth={20} /> +<Select variant="outlined" label="Gender" />
Merge the
selectMenu
slot intoselect
. SlotselectMenu
was redundant. Theroot
slot is no longer applied to the select, but to the root.-<Select classes={{ root: 'class1', select: 'class2', selectMenu: 'class3' }} /> +<Select classes={{ select: 'class1 class2 class3' }} />
Skeleton
Move the component from the lab to the core. The component is now stable.
-import Skeleton from '@material-ui/lab/Skeleton'; +import Skeleton from '@material-ui/core/Skeleton';
You can use our
moved-lab-modules
codemod for automatic migration.Rename
circle
tocircular
andrect
torectangular
for consistency. The possible values should be adjectives, not nouns:-<Skeleton variant="circle" /> -<Skeleton variant="rect" /> -<Skeleton classes={{ circle: 'custom-circle-classname', rect: 'custom-rect-classname', }} /> +<Skeleton variant="circular" /> +<Skeleton variant="rectangular" /> +<Skeleton classes={{ circular: 'custom-circle-classname', rectangular: 'custom-rect-classname', }} />
Slider
TypeScript: The
event
inonChange
is no longer typed as aReact.ChangeEvent
butReact.SyntheticEvent
.-<Slider onChange={(event: React.ChangeEvent<{}>, value: unknown) => {}} /> +<Slider onChange={(event: React.SyntheticEvent, value: unknown) => {}} />
The
ValueLabelComponent
prop is now part of thecomponents
prop.-<Slider ValueLabelComponent={CustomValueLabel} /> +<Slider components={{ ValueLabel: CustomValueLabel }} />
The
ThumbComponent
prop is not part of thecomponents
prop.-<Slider ThumbComponent={CustomThumb} /> +<Slider components={{ Thumb: CustomThumb }} />
Snackbar
The notification now displays at the bottom left on large screens. This better matches the behavior of Gmail, Google Keep, material.io, etc. You can restore the previous behavior with:
-<Snackbar /> +<Snackbar anchorOrigin={{ vertical: 'bottom', horizontal: 'center' }} />
The onE* transition props were removed. Use TransitionProps instead.
<Snackbar - onEnter={onEnter} - onEntered={onEntered}, - onEntering={onEntered}, - onExit={onEntered}, - onExited={onEntered}, - onExiting={onEntered} + TransitionProps={{ + onEnter, + onEntered, + onEntering, + onExit, + onExited, + onExiting, + }} />
SpeedDial
Move the component from the lab to the core. The component is now stable.
-import SpeedDial from '@material-ui/lab/SpeedDial'; -import SpeedDialAction from '@material-ui/lab/SpeedDialAction'; -import SpeedDialIcon from '@material-ui/lab/SpeedDialIcon'; +import SpeedDial from '@material-ui/core/SpeedDial'; +import SpeedDialAction from '@material-ui/core/SpeedDialAction'; +import SpeedDialIcon from '@material-ui/core/SpeedDialIcon';
You can use our
moved-lab-modules
codemod for automatic migration.
Stepper
The root component (Paper) was replaced with a div. Stepper no longer has elevation, nor inherits Paper's props. This change is meant to encourage composition.
-<Stepper elevation={2}> - <Step> - <StepLabel>Hello world</StepLabel> - </Step> -</Stepper> +<Paper square elevation={2}> + <Stepper> + <Step> + <StepLabel>Hello world</StepLabel> + </Step> + </Stepper> +<Paper>
Remove the built-in 24px padding.
-<Stepper> - <Step> - <StepLabel>Hello world</StepLabel> - </Step> -</Stepper> +<Stepper style={{ padding: 24 }}> + <Step> + <StepLabel>Hello world</StepLabel> + </Step> +</Stepper>
SvgIcon
The default value of
fontSize
was changed fromdefault
tomedium
for consistency. In the unlikey event that you were using the valuedefault
, the prop can be removed:-<SvgIcon fontSize="default"> +<SvgIcon> <path d="M10 20v-6h4v6h5v-8h3L12 3 2 12h3v8z" /> </SvgIcon>
Switch
Remove the second argument from
onChange
. You can pull out the checked state by accessingevent.target.checked
.function MySwitch() { - const handleChange = (event: React.ChangeEvent<HTMLInputElement>, checked: boolean) => { + const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { + const checked = event.target.checked; }; return <Switch onChange={handleChange} />; }
The switch color prop is now "primary" by default. To continue using the "secondary" color, you must explicitly indicate
secondary
. This brings the switch closer to the Material Design specification.-<Switch /> +<Switch color="secondary" />
Table
The customization of the table pagination's actions labels must be done with the
getItemAriaLabel
prop. This increases consistency with thePagination
component.<TablePagination - backIconButtonText="Avant" - nextIconButtonText="Après + getItemAriaLabel={…}
Rename
onChangeRowsPerPage
toonRowsPerPageChange
andonChangePage
toonPageChange
due to API consistency.<TablePagination - onChangeRowsPerPage={()=>{}} - onChangePage={()=>{}} + onRowsPerPageChange={()=>{}} + onPageChange={()=>{}}
Separate classes for different table pagination labels. This allows simpler customizations.
<TablePagination - classes={{ caption: 'foo' }} + classes={{ selectLabel: 'foo', displayedRows: 'foo' }} />
Move the custom class on
input
toselect
. Theinput
key is being applied on another element.<TablePagination - classes={{ input: 'foo' }} + classes={{ select: 'foo' }} />
Rename the
default
value of thepadding
prop tonormal
.-<Table padding="default" /> -<TableCell padding="default" /> +<Table padding="normal" /> +<TableCell padding="normal" />
Tabs
Change the default
indicatorColor
andtextColor
prop values to "primary". This is done to match the most common use cases with Material Design.-<Tabs /> +<Tabs indicatorColor="primary" textColor="inherit" />
TypeScript: The
event
inonChange
is no longer typed as aReact.ChangeEvent
butReact.SyntheticEvent
.-<Tabs onChange={(event: React.ChangeEvent<{}>, value: unknown) => {}} /> +<Tabs onChange={(event: React.SyntheticEvent, value: unknown) => {}} />
The API that controls the scroll buttons has been split it in two props.
- The
scrollButtons
prop controls when the scroll buttons are displayed depending on the space available. - The
allowScrollButtonsMobile
prop removes the CSS media query that systematically hide the scroll buttons on mobile.
-<Tabs scrollButtons="on" /> -<Tabs scrollButtons="desktop" /> -<Tabs scrollButtons="off" /> +<Tabs scrollButtons allowScrollButtonsMobile /> +<Tabs scrollButtons /> +<Tabs scrollButtons={false} />
- The
TextField
Change the default variant from
standard
tooutlined
. Standard has been removed from the Material Design Guidelines.-<TextField value="Standard" /> -<TextField value="Outlined" variant="outlined" /> +<TextField value="Standard" variant="standard" /> +<TextField value="Outlined" />
This codemod will automatically update your code.
Rename
rowsMax
prop withmaxRows
for consistency with HTML attributes.-<TextField rowsMax={6}> +<TextField maxRows={6}>
Better isolate the fixed textarea height behavior to the dynamic one. You need to use the
minRows
prop in the following case:-<TextField rows={2} maxRows={5} /> +<TextField minRows={2} maxRows={5} />
Change ref forwarding expectations on custom
inputComponent
. The component should forward theref
prop instead of theinputRef
prop.-function NumberFormatCustom(props) { - const { inputRef, onChange, ...other } = props; +const NumberFormatCustom = React.forwardRef(function NumberFormatCustom( + props, + ref, +) { const { onChange, ...other } = props; return ( <NumberFormat {...other} - getInputRef={inputRef} + getInputRef={ref}
Rename
marginDense
andinputMarginDense
classes tosizeSmall
andinputSizeSmall
to match the prop.-<Input margin="dense" /> +<Input size="small" />
Set the InputAdornment
position
prop tostart
orend
. Usestart
if used as the value of thestartAdornment
prop. Useend
if used as the value of theendAdornment
prop.-<TextField startAdornment={<InputAdornment>Kg</InputAdornment>} /> -<TextField endAdornment={<InputAdornment>Kg</InputAdornment>} /> +<TextField startAdornment={<InputAdornment position="start">Kg</InputAdornment>} /> +<TextField endAdornment={<InputAdornment position="end">Kg</InputAdornment>} />
TextareaAutosize
Remove the
rows
prop, use theminRows
prop instead. This change aims to clarify the behavior of the prop.-<TextareaAutosize rows={2} /> +<TextareaAutosize minRows={2} />
Rename
rowsMax
prop withmaxRows
for consistency with HTML attributes.-<TextareAutosize rowsMax={6}> +<TextareAutosize maxRows={6}>
Rename
rowsMin
prop withminRows
for consistency with HTML attributes.-<TextareAutosize rowsMin={1}> +<TextareAutosize minRows={1}>
ToggleButton
Move the component from the lab to the core. The component is now stable.
-import ToggleButton from '@material-ui/lab/ToggleButton'; -import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'; +import ToggleButton from '@material-ui/core/ToggleButton'; +import ToggleButtonGroup from '@material-ui/core/ToggleButtonGroup';
You can use our
moved-lab-modules
codemod for automatic migration.
Tooltip
Tooltips are now interactive by default.
The previous default behavior failed success criterion 1.4.3 ("hoverable") in WCAG 2.1. To reflect the new default value, the prop was renamed to
disableInteractive
. If you want to restore the old behavior (thus not reaching level AA), you can apply the following diff:-<Tooltip> +<Tooltip disableInteractive> # Interactive tooltips no longer need the `interactive` prop. -<Tooltip interactive> +<Tooltip>
Typography
Remove the
srOnly
variant. You can use thevisuallyHidden
utility in conjunction with thesx
prop instead.+import { visuallyHidden } from '@material-ui/utils'; -<Typography variant="srOnly">Create a user</Typography> +<span style={visuallyHidden}>Create a user</span>
The following
classes
and style overrides keys were removed: "colorInherit", "colorPrimary", "colorSecondary", "colorTextPrimary", "colorTextSecondary", "colorError", "displayInline" and "displayBlock". These props are now considered part of the system, not on theTypography
component itself. If you still wish to add overrides for them, you can use thetheme.components.MuiTypography.variants
options. For exampleconst theme = createTheme({ components: { MuiTypography: { - styleOverrides: { - colorSecondary: { - marginTop: '20px', - }, - }, + variants: { + props: { color: "secondary" }, + style: { + marginTop: '20px', + }, + }], }, }, });
@material-ui/core/styles
createGenerateClassName
The
createGenerateClassName
function is no longer exported from@material-ui/core/styles
. You should import it directly from@material-ui/styles
.-import { createGenerateClassName } from '@material-ui/core/styles'; +import { createGenerateClassName } from '@material-ui/styles';
jssPreset
The
jssPreset
object is no longer exported from@material-ui/core/styles
. You should import it directly from@material-ui/styles
.-import { jssPreset } from '@material-ui/core/styles'; +import { jssPreset } from '@material-ui/styles';
MuiThemeProvider
The
MuiThemeProvider
component is no longer exported from@material-ui/core/styles
. UseThemeProvider
instead.-import { MuiThemeProvider } from '@material-ui/core/styles'; +import { ThemeProvider } from '@material-ui/core/styles';
ServerStyleSheets
The
ServerStyleSheets
component is no longer exported from@material-ui/core/styles
. You should import it directly from@material-ui/styles
.-import { ServerStyleSheets } from '@material-ui/core/styles'; +import { ServerStyleSheets } from '@material-ui/styles';
styled
The
styled
JSS utility is no longer exported from@material-ui/core/styles
. You can use@material-ui/styles/styled
instead. Make sure to add aThemeProvider
at the root of your application, as thedefaultTheme
is no longer available. If you are using this utility together with@material-ui/core
, it's recommended you use theThemeProvider
component from@material-ui/core/styles
instead.-import { styled } from '@material-ui/core/styles'; +import { styled } from '@material-ui/styles'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; +const theme = createTheme(); const MyComponent = styled('div')(({ theme }) => ({ background: theme.palette.primary.main })); function App(props) { - return <MyComponent />; + return <ThemeProvider theme={theme}><MyComponent {...props} /></ThemeProvider>; }
Note: If you would like to move
StylesProvider
The
StylesProvider
component is no longer exported from@material-ui/core/styles
. You should import it directly from@material-ui/styles
.-import { StylesProvider } from '@material-ui/core/styles'; +import { StylesProvider } from '@material-ui/styles';
useThemeVariants
The
useThemeVariants
hook is no longer exported from@material-ui/core/styles
. You should import it directly from@material-ui/styles
.-import { useThemeVariants } from '@material-ui/core/styles'; +import { useThemeVariants } from '@material-ui/styles';
withStyles
Replace the
innerRef
prop with theref
prop. Refs are now automatically forwarded to the inner component.import * as React from 'react'; import { withStyles } from '@material-ui/core/styles'; const MyComponent = withStyles({ root: { backgroundColor: 'red', }, })(({ classes }) => <div className={classes.root} />); function MyOtherComponent(props) { const ref = React.useRef(); - return <MyComponent innerRef={ref} />; + return <MyComponent ref={ref} />; }
withTheme
The
withTheme
HOC utility has been removed from the@material-ui/core/styles
package. You can use@material-ui/styles/withTheme
instead. Make sure to add aThemeProvider
at the root of your application, as thedefaultTheme
is no longer available. If you are using this utility together with@material-ui/core
, it's recommended you use theThemeProvider
component from@material-ui/core/styles
instead.-import { withTheme } from '@material-ui/core/styles'; +import { withTheme } from '@material-ui/styles'; +import { createTheme, ThemeProvider } from '@material-ui/core/styles'; +const theme = createTheme(); const MyComponent = withTheme(({ theme }) => <div>{props.theme.direction}</div>); function App(props) { - return <MyComponent />; + return <ThemeProvider theme={theme}><MyComponent {...props} /></ThemeProvider>; }
Replace the
innerRef
prop with theref
prop. Refs are now automatically forwarded to the inner component.import * as React from 'react'; import { withTheme } from '@material-ui/core/styles'; const MyComponent = withTheme(({ theme }) => <div>{props.theme.direction}</div>); function MyOtherComponent(props) { const ref = React.useRef(); - return <MyComponent innerRef={ref} />; + return <MyComponent ref={ref} />; }
withWidth
- This HOC was removed. There's an alternative using the
useMediaQuery
hook on this page.
@material-ui/types
- Rename the exported
Omit
type in@material-ui/types
. The module is now calledDistributiveOmit
. The change removes the confusion with the built-inOmit
helper introduced in TypeScript v3.5. The built-inOmit
, while similar, is non-distributive. This leads to differences when applied to union types. See this StackOverflow answer for further details.
-import { Omit } from '@material-ui/types';
+import { DistributiveOmit } from '@material-ui/types';