CSS Layers
Learn how to generate Material UI styles with cascade layers.
Overview
Cascade layers are a new CSS feature that allows you to control the order in which styles are applied to elements. If you are not familiar with cascade layers, we recommend reading the MDN documentation for a detailed overview.
Some of the benefits of using cascade layers include:
- Improved specificity: Cascade layers let you control the order of the styles, which can help avoid specificity conflicts. For example, you can theme a component without hitting the default specificity of the styles.
- Better integration with CSS frameworks: With cascade layers, you can use Tailwind CSS v4 utility classes to override Material UI styles without specifying
!important
directive. - Better debuggability: Cascade layers appear in the browser's dev tools, making it easier to see which styles are applied and in what order.
Single layer
This method creates a single layer, namely @layer mui
, for all Material UI components and global styles.
This method is suitable for integrating with other styling solutions, such as Tailwind CSS v4, that use the @layer
directive.
Next.js App Router
Start by configuring Material UI with Next.js in the App Router integration guide. Then follow these steps:
- Enable the CSS layer feature in the root layout:
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
export default function RootLayout() {
return (
<html lang="en" suppressHydrationWarning>
<body>
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
{/* Your app */}
</AppRouterCacheProvider>
</body>
</html>
);
}
- Configure the layer order at the top of a CSS file to work with Tailwind CSS v4:
@layer theme, base, mui, components, utilities;
Next.js Pages Router
Start by configuring Material UI with Next.js in the Pages Router integration guide. Then follow these steps:
- Enable the CSS layer feature in a custom
_document
:
import {
createCache,
documentGetInitialProps,
} from '@mui/material-nextjs/v15-pagesRouter';
// ...
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const finalProps = await documentGetInitialProps(ctx, {
emotionCache: createCache({ enableCssLayer: true }),
});
return finalProps;
};
- Configure the layer order with the
GlobalStyles
component to work with Tailwind CSS v4—it must be the first child of theAppCacheProvider
:
import { AppCacheProvider } from '@mui/material-nextjs/v15-pagesRouter';
import GlobalStyles from '@mui/material/GlobalStyles';
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
return (
<AppCacheProvider {...props}>
<GlobalStyles styles="@layer theme, base, mui, components, utilities;" />
<Component {...pageProps} />
</AppCacheProvider>
);
}
Vite or any other SPA
Make the following changes in src/main.tsx
:
- Pass the
enableCssLayer
prop to theStyledEngineProvider
component. - Configure the layer order with the
GlobalStyles
component to work with Tailwind CSS v4.
import { StyledEngineProvider } from '@mui/material/styles';
import GlobalStyles from '@mui/material/GlobalStyles';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<StyledEngineProvider enableCssLayer>
<GlobalStyles styles="@layer theme, base, mui, components, utilities;" />
{/* Your app */}
</StyledEngineProvider>
</React.StrictMode>,
);
Multiple layers
On top of the single layer, you can split styles into multiple layers to better organize them within Material UI.
This makes theming and overriding styles through the sx
prop easier.
Follow the steps from the previous section to enable the CSS layer feature.
Then, create a new file and export the component that wraps the ThemeProvider
from Material UI.
Finally, pass the experimental_modularCssLayers: true
option to the createTheme
function:
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
experimental_modularCssLayers: true,
});
export default function AppTheme({ children }: { children: ReactNode }) {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
Helper text goes here
When this feature is enabled, Material UI generates these layers:
@layer mui.global
: The global styles fromGlobalStyles
andCssBaseline
components.@layer mui.default
: The base styles for all Material UI components.@layer mui.theme
: The theme styles for all Material UI components.@layer mui.custom
: The custom styles for non-Material UI styled components.@layer mui.sx
: The styles from thesx
prop.
If you want to integrate with other styling solutions, such as Tailwind CSS v4, you can specify the layer order as a value to the experimental_modularCssLayers
field, Material UI will replace the mui
identifier with the correct order:
const theme = createTheme({
- experimental_modularCssLayers: true,
+ experimental_modularCssLayers: '@layer theme, base, mui, components, utilities;',
});
Below are full examples of how to set up multiple layers with Tailwind CSS v4 in different frameworks.
Next.js App Router
'use client';
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
experimental_modularCssLayers: '@layer theme, base, mui, components, utilities;',
});
export default function AppTheme({ children }: { children: ReactNode }) {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
import AppTheme from '../theme';
export default function RootLayout() {
return (
<html lang="en" suppressHydrationWarning>
<body>
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
<AppTheme>{/* Your app */}</AppTheme>
</AppRouterCacheProvider>
</body>
</html>
);
}
Next.js Pages Router
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
experimental_modularCssLayers: '@layer theme, base, mui, components, utilities;',
});
export default function AppTheme({ children }: { children: ReactNode }) {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
import AppTheme from '../src/theme';
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
return (
<AppCacheProvider {...props}>
<AppTheme>
<Component {...pageProps} />
</AppTheme>
</AppCacheProvider>
);
}
import {
createCache,
documentGetInitialProps,
} from '@mui/material-nextjs/v15-pagesRouter';
MyDocument.getInitialProps = async (ctx: DocumentContext) => {
const finalProps = await documentGetInitialProps(ctx, {
emotionCache: createCache({ enableCssLayer: true }),
});
return finalProps;
};
Vite or any other SPA
import { createTheme, ThemeProvider } from '@mui/material/styles';
const theme = createTheme({
experimental_modularCssLayers: '@layer theme, base, mui, components, utilities;',
});
export default function AppTheme({ children }: { children: ReactNode }) {
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
import AppTheme from './theme';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<StyledEngineProvider enableCssLayer>
<AppTheme>{/* Your app */}</AppTheme>
</StyledEngineProvider>
</React.StrictMode>,
);