Skip to content

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.

"dependencies": {
  "@material-ui/core": "^5.0.0-alpha.1"
}

Or run

npm install @material-ui/core@next

or

yarn add @material-ui/core@next

Handling breaking changes

non-ref-forwarding class components

Support for non-ref-forwarding class components in the component prop or as an 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>)

Theme

For a smoother transition, the adaptV4Theme helper allows you to iteratively upgrade to the new theme structure.

-import { createMuiTheme } from '@material-ui/core/styles';
+import { createMuiTheme, adaptV4Theme } from '@material-ui/core/styles';

-const theme = createMuitheme({
+const theme = createMuitheme(adaptV4Theme({
  // v4 theme
-});
+}));

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'

    You can restore the previous behavior with:

    -const theme = createMuiTheme();
    +const theme = createMuiTheme({
    +  spacing: x => x * 8,
    +});
  • The theme.palette.text.hint key was unused in Material-UI components, and has been removed.

import { createMuiTheme } from '@material-ui/core/styles';

-const theme = createMuitheme(),
+const theme = createMuitheme({
+  palette: { text: { hint: 'rgba(0, 0, 0, 0.38)' } },
+});
import { createMuiTheme } from '@material-ui/core/styles';

-const theme = createMuitheme({palette: { type: 'dark' }}),
+const theme = createMuitheme({
+  palette: { type: 'dark', text: { hint: 'rgba(0, 0, 0, 0.38)' } },
+});
  • The components' definition inside the theme were restructure under the components key, to allow people easier discoverability about the definitions regarding one component.
  1. props
import { createMuiTheme } from '@material-ui/core/styles';

const theme = createMuitheme({
-  props: {
-    MuiButton: {
-      disableRipple: true,
-    },
-  },
+  components: {
+    MuiButton: {
+      defaultProps: {
+        disableRipple: true,
+      },
+    },
+  },
});
  1. overrides
import { createMuiTheme } from '@material-ui/core/styles';

const theme = createMuitheme({
-  overrides: {
-    MuiButton: {
-      root: { padding: 0 },
-    },
-  },
+  components: {
+    MuiButton: {
+      styleOverrides: {
+        root: { padding: 0 },
+      },
+    },
+  },
});

Avatar

  • Rename circle to circular for consistency. The possible values should be adjectives, not nouns:

    -<Avatar variant="circle">
    -<Avatar classes={{ circle: 'className' }}>
    +<Avatar variant="circular">
    +<Avatar classes={{ circular: 'className' }}>

Badge

  • Rename circle to circular and rectangle to rectangular 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 in onChange is no longer typed as a React.ChangeEvent but React.SyntheticEvent.

    -<BottomNavigation onChange={(event: React.ChangeEvent<{}>) => {}} />
    +<BottomNavigation onChange={(event: React.SyntheticEvent) => {}} />

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 />

CircularProgress

  • The static variant has been merged into the determinate 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 renamed collapsedSize 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' }}>

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,
    +  }}
    />

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 to Accordion 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 in onChange is no longer typed as a React.ChangeEvent but React.SyntheticEvent.

    -<Accordion onChange={(event: React.ChangeEvent<{}>, expanded: boolean) => {}} />
    +<Accordion onChange={(event: React.SyntheticEvent, expanded: boolean) => {}} />
  • Rename focused to focusVisible for consistency:

    <Accordion
      classes={{
    -    focused: 'custom-focus-visible-classname',
    +    focusVisible: 'custom-focus-visible-classname',
      }}
    />

Fab

  • Rename round to circular for consistency. The possible values should be adjectives, not nouns:

    -<Fab variant="round">
    +<Fab variant="circular">

Grid

  • Rename justify prop with justifyContent to be aligned with the CSS property name.

    -<Grid justify="center">
    +<Grid justifyContent="center">

GridList

  • Rename the GridList components to ImageList to align with the current Material Design naming.
  • Rename the GridList spacing prop to gap to align with the CSS attribute.
  • Rename the GridList cellHeight prop to rowHieght.
  • Add the variant prop to GridList.
  • Rename the GridListItemBar actionPosition prop to position. (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>

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,
    +  }}
    >

Modal

  • 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.

Pagination

  • Rename round to circular for consistency. The possible values should be adjectives, not nouns:

    -<Pagination shape="round">
    +<Pagination shape="circular">

PaginationItem

  • Rename round to circular for consistency. The possible values should be adjectives, not nouns:

    -<PaginationItem shape="round">
    +<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,
    +  }}
    />

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.

Rating

  • Change the default empty icon to improve accessibility. If you have a custom icon prop but no emptyIcon prop, you can restore the previous behavior with:

    <Rating
      icon={customIcon}
    + emptyIcon={null}
    />
  • Rename visuallyhidden to visuallyHidden 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 on ReactDOM.findDOMNode which is deprecated in React.StrictMode.

    -<RootRef rootRef={ref}>
    -  <Button />
    -</RootRef>
    +<Button ref={ref} />

Skeleton

  • Rename circle to circular and rect to rectangular 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 in onChange is no longer typed as a React.ChangeEvent but React.SyntheticEvent.

    -<Slider onChange={(event: React.ChangeEvent<{}>, value: unknown) => {}} />
    +<Slider onChange={(event: React.SyntheticEvent, value: unknown) => {}} />

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,
    +  }}
    />

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>

TablePagination

  • The customization of the table pagination's actions labels must be done with the getItemAriaLabel prop. This increases consistency with the Pagination component.

    <TablePagination
    - backIconButtonText="Avant"
    - nextIconButtonText="Après
    + getItemAriaLabel={…}

Tabs

  • TypeScript: The event in onChange is no longer typed as a React.ChangeEvent but React.SyntheticEvent.

    -<Tabs onChange={(event: React.ChangeEvent<{}>, value: unknown) => {}} />
    +<Tabs onChange={(event: React.SyntheticEvent, value: unknown) => {}} />

TextField

  • 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} />
  • Rename rowsMax prop with maxRows for consistency with HTML attributes.

    -<TextField rowsMax={6}>
    +<TextField maxRows={6}>

TextareaAutosize

  • Remove the rows prop, use the minRows prop instead. This change aims to clarify the behavior of the prop.

    -<TextareaAutosize rows={2} />
    +<TextareaAutosize minRows={2} />
  • Rename rowsMax prop with maxRows for consistency with HTML attributes.

    -<TextareAutosize rowsMax={6}>
    +<TextareAutosize maxRows={6}>
  • Rename rowsMin prop with minRows for consistency with HTML attributes.

    -<TextareAutosize rowsMin={1}>
    +<TextareAutosize minRows={1}>

Typography

  • Replace the srOnly prop so as to not duplicate the capabilities of System:

    -import Typography from '@material-ui/core/Typography';
    +import { visuallyHidden } from '@material-ui/system';
    +import styled from 'styled-component';
    
    +const Span = styled('span')(visuallyHidden);
    
    -<Typography variant="srOnly">Create a user</Typography>
    +<Span>Create a user</Span>