Material-UI v6 Migration: Key Breaking Changes from v5
Material-UI v6 removes the UMD bundle, stabilizes the Grid2 API with new prop structures, consolidates LoadingButton into the core Button, and updates component behaviors like Accordion headings and ListItem composition that require manual code updates or codemods to migrate safely from v5.
Material-UI v6 introduces a focused set of breaking changes designed to modernize the library, reduce bundle size, and prepare for React 19 and Server Component support. This guide examines the specific API adjustments implemented in the mui/material-ui repository that you must address when upgrading from v5, referencing the official migration guide at docs/data/material/migration/upgrade-to-v6/upgrade-to-v6.md.
Grid2 API Stabilization and Prop Restructuring
The most significant component-level change in Material-UI v6 migration involves the stabilization of the Grid2 component, previously exported as Unstable_Grid2.
Removal of the Unstable Prefix
As implemented in packages/mui-material/src/Grid2/Grid2.js, the component is now stable and imports must change from @mui/material/Unstable_Grid2 to @mui/material/Grid2 (or { Grid2 } from the main package).
New size and offset Object Syntax
The responsive breakpoint props (xs, sm, md, lg, xl) and offset props (xsOffset, smOffset, etc.) are replaced by unified size and offset objects. According to the source code, the old flat prop structure is no longer supported.
Update your JSX from the v5 syntax:
// v5 - No longer valid
<Grid2 xs={12} sm={6} xsOffset={2} />
To the v6 object-based approach:
import { Grid2 } from '@mui/material';
// v6 - Correct syntax
<Grid2
size={{ xs: 12, sm: 6 }}
offset={{ xs: 2 }}
/>
CSS Gap-Based Spacing
Grid2 now uses the CSS gap property for spacing instead of the previous implementation. The disableEqualOverflow prop has been removed, and grids no longer automatically grow to full width. You must explicitly control sizing via the size prop.
Grid2 Migration Codemod
The repository provides an automated migration path via packages/mui-codemod/src/v6.0.0/grid-v2-props/grid-v2-props.js. Run this codemod to automatically convert imports and prop structures:
npx @mui/codemod v6.0.0/grid-v2-props <path>
Button and ListItem Composition Changes
Material-UI v6 consolidates button-related functionality and removes legacy ListItem behaviors that duplicated button capabilities.
LoadingButton Removal and Core Button Loading State
As of v6.4.0, the LoadingButton component from @mui/lab has been removed. The loading state is now a core feature of the standard Button component. The source file packages/mui-material/src/LoadingButton/LoadingButton.js no longer exists in v6.
Migrate by changing your imports and component usage:
import Button from '@mui/material/Button';
// Replace <LoadingButton loading ... /> with:
<Button loading variant="contained">
Submit
</Button>
ListItem Prop Removal and ListItemButton Migration
The ListItem component in packages/mui-material/src/ListItem/ListItem.js no longer accepts the button, autoFocus, disabled, or selected props. These features are now exclusively handled by ListItemButton.
Update your code to use the dedicated component and import its classes from the new location:
import ListItemButton from '@mui/material/ListItemButton';
import { listItemButtonClasses } from '@mui/material/ListItemButton';
// Replace <ListItem button selected ... />
<ListItemButton selected className={listItemButtonClasses.root}>
Item Text
</ListItemButton>
The codemod at packages/mui-codemod/src/v6.0.0/list-item-button-prop/list-item-button-prop.js automates this conversion:
npx @mui/codemod v6.0.0/list-item-button-prop <path>
Component DOM and Accessibility Updates
Several components underwent DOM structure changes to improve accessibility and semantic correctness.
AccordionSummary Heading Structure
The AccordionSummary component, as implemented in packages/mui-material/src/Accordion/Accordion.js, is now wrapped in a default <h3> heading element (which contains the button element). This affects CSS selectors and accessibility trees.
If you need to change the heading level for semantic hierarchy, use the new slotProps.heading.component API:
import AccordionSummary from '@mui/material/AccordionSummary';
<AccordionSummary
expandIcon={<ExpandMoreIcon />}
slotProps={{ heading: { component: 'h4' } }} // Changes from h3 to h4
>
Section Title
</AccordionSummary>
Divider Vertical Element Change
Vertical Divider components now render as <div> elements instead of <hr>. Update any CSS selectors that target the hr tag specifically:
/* v5 - No longer matches */
.MuiDivider-vertical hr { ... }
/* v6 - Use the root class instead */
.MuiDivider-root.MuiDivider-vertical { ... }
Chip Focus Retention Behavior
The Chip component now retains focus when the Esc key is pressed, whereas v5 blurred the component. If your application logic depends on the previous blur behavior, implement a custom onKeyUp handler to manually blur the element.
Autocomplete onInputChange Reason Values
The onInputChange callback in Autocomplete now receives additional reason values: "blur", "selectOption", and "removeOption". Update your event handlers to account for these new cases:
<Autocomplete
onInputChange={(event, value, reason) => {
if (reason === 'blur' || reason === 'selectOption') {
// Handle new v6 reasons
}
}}
/>
Infrastructure and Type System Changes
Material-UI v6 migration requires updates to your build configuration and type definitions.
UMD Bundle Removal
The UMD bundle is no longer distributed. Applications using UMD must switch to ESM-based imports or CDN alternatives like esm.sh. This change affects how you load the library in browser environments without a bundler.
Typography Color Prop Removal
The color prop is no longer a system prop on Typography. Custom colors must now be applied via the sx prop:
import Typography from '@mui/material/Typography';
// v5 - Removed
<Typography color="primary.main">
// v6 - Correct approach
<Typography sx={{ color: theme => theme.palette.primary.main }}>
Box Component Prop Restriction
The component prop has been removed from BoxOwnProps type definitions. When extending or styling Box, use a native element wrapper or type casting as described in the migration guide.
useMediaQuery Type Cleanup
Deprecated type aliases (MuiMediaQueryList, MuiMediaQueryListEvent, MuiMediaQueryListListener) have been removed from the useMediaQuery hook. Use standard DOM types (MediaQueryList, MediaQueryListEvent) instead.
CssVarsProvider Stabilization
The experimental prefixes have been dropped from CssVarsProvider and extendTheme. Import these utilities directly without the experimental_ prefix:
import { CssVarsProvider, extendTheme } from '@mui/material/styles';
Theming and Testing Adjustments
Color-Mode Utility Replacement
The theme.palette.mode property usage for conditional styling is replaced by the theme.applyStyles() method. Update your theme overrides:
// v5 - Deprecated pattern
sx={{
color: theme.palette.mode === 'dark' ? '#fff' : '#000',
}}
// v6 - Modern approach
sx={{
...theme.applyStyles('dark', { color: '#fff' }),
...theme.applyStyles('light', { color: '#000' }),
}}
The codemod at packages/mui-codemod/src/v6.0.0/theme-v6/theme-v6.js handles this conversion automatically:
npx @mui/codemod v6.0.0/theme-v6 <path>
Ripple Effect Testing Requirements
Performance optimizations to the ripple effect require updates to your test suites. Interaction calls that fire events on buttons, checkboxes, chips, and other ripple-enabled components must now be wrapped in act and awaited:
import { act } from 'react-dom/test-utils';
await act(async () => {
fireEvent.click(button);
});
Automating Migration with Codemods
The mui/material-ui repository provides three primary codemods to streamline your Material-UI v6 migration:
grid-v2-props(packages/mui-codemod/src/v6.0.0/grid-v2-props/grid-v2-props.js) - Updates Grid2 imports and converts breakpoint props to the new object syntax.list-item-button-prop(packages/mui-codemod/src/v6.0.0/list-item-button-prop/list-item-button-prop.js) - TransformsListItembutton props intoListItemButtoncomponents.theme-v6(packages/mui-codemod/src/v6.0.0/theme-v6/theme-v6.js) - Convertstheme.palette.modechecks totheme.applyStyles()calls.
Run these codemods before manual adjustments to minimize migration effort.
Summary
- Grid2 requires updating imports from
Unstable_Grid2toGrid2and converting responsive props (xs,sm) to the newsizeandoffsetobject syntax. - LoadingButton from
@mui/labis removed; use the coreButtoncomponent with theloadingprop instead. - ListItem no longer accepts
button,selected,disabled, orautoFocusprops; migrate toListItemButtonand importlistItemButtonClassesfrom the new location. - AccordionSummary now renders within an
<h3>by default; useslotProps.heading.componentto customize the heading level. - Typography removes the
colorsystem prop; apply custom colors via thesxprop. - UMD bundles are discontinued; switch to ESM imports or modern CDN providers.
- Testing requires wrapping ripple interactions in
actand awaiting them due to performance optimizations.
Frequently Asked Questions
How do I migrate Grid2 from Material-UI v5 to v6?
Run the grid-v2-props codemod to automatically convert Unstable_Grid2 imports to Grid2 and transform flat breakpoint props like xs={12} into the object syntax size={{ xs: 12 }}. After running the codemod, verify that spacing behaves correctly since Grid2 now uses CSS gap and no longer expands to full width by default.
What happened to LoadingButton in Material-UI v6?
LoadingButton was removed from @mui/lab in v6.4.0 and its functionality was merged into the core Button component. Change your imports from @mui/lab/LoadingButton to @mui/material/Button and add the loading prop to enable the loading state with the circular progress indicator.
Why did my ListItem buttons stop working after upgrading to v6?
The button, selected, disabled, and autoFocus props were removed from ListItem to enforce proper component composition. You must replace <ListItem button ... /> with <ListItemButton ... /> and update any class imports to use listItemButtonClasses from @mui/material/ListItemButton. The list-item-button-prop codemod automates this migration.
How do I handle dark mode styling without theme.palette.mode in v6?
Material-UI v6 introduces theme.applyStyles() as the preferred method for color-mode-specific styling. Replace conditional logic checking theme.palette.mode with theme.applyStyles('dark', { ... }) or theme.applyStyles('light', { ... }). The theme-v6 codemod can automate this conversion across your codebase.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →