Next.js integration
Learn how to use Material UI with Next.js
App Router
This section walks through the Material UI integration with the Next.js App Router, an evolution of the Pages Router, and, currently, the recommended way of building new Next.js applications starting from version 13.
Installing the dependencies
Start by ensuring that you already have @mui/material
and next
installed.
Then, run one of the following commands to install the dependencies:
npm install @mui/material-nextjs @emotion/cache
Configuration
Inside app/layout.tsx
, import the AppRouterCacheProvider
and wrap all elements under the <body>
with it:
+import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
// or `v1X-appRouter` if you are using Next.js v1X
export default function RootLayout(props) {
return (
<html lang="en">
<body>
+ <AppRouterCacheProvider>
{props.children}
+ </AppRouterCacheProvider>
</body>
</html>
);
}
Custom cache (optional)
Use the options
prop to override the default cache options—for example, the code snippet below shows how to change the CSS key to css
(the default is mui
):
<AppRouterCacheProvider
+ options={{ key: 'css' }}
>
{children}
</AppRouterCacheProvider>
Theming
Create a new file and export a custom theme that includes the 'use client';
directive:
// src/theme.ts
'use client';
import { Roboto } from 'next/font/google';
import { createTheme } from '@mui/material/styles';
const roboto = Roboto({
weight: ['300', '400', '500', '700'],
subsets: ['latin'],
display: 'swap',
});
const theme = createTheme({
typography: {
fontFamily: roboto.style.fontFamily,
},
});
export default theme;
Then in src/app/layout.tsx
, pass the theme to ThemeProvider
:
// app/layout.tsx
import { AppRouterCacheProvider } from '@mui/material-nextjs/v13-appRouter';
+import { ThemeProvider } from '@mui/material/styles';
+import theme from '../theme';
export default function RootLayout(props) {
const { children } = props;
return (
<html lang="en">
<body>
<AppRouterCacheProvider>
+ <ThemeProvider theme={theme}>
{children}
+ </ThemeProvider>
</AppRouterCacheProvider>
</body>
</html>
);
}
To learn more about theming, check out the theming guide page.
CSS theme variables
If you want to use CSS theme variables, use the extendTheme
and CssVarsProvider
utilities instead:
// src/theme.ts
'use client';
-import { createTheme } from '@mui/material/styles';
+import { extendTheme } from '@mui/material/styles';
// app/layout.tsx
-import { ThemeProvider } from '@mui/material/styles';
+import { CssVarsProvider } from '@mui/material/styles';
Learn more about the advantages of CSS theme variables.
Using other styling solutions
If you are using a styling solution other than Emotion to customize Material UI components, set enableCssLayer: true
in the options
prop:
<AppRouterCacheProvider options={{ enableCssLayer: true }}>
This option ensures that the styles generated by Material UI will be wrapped in a CSS @layer mui
rule, which is overridden by anonymous layer styles when using Material UI with CSS Modules, Tailwind CSS, or even plain CSS without using @layer
.
To learn more about it, see the MDN CSS layer documentation.
Pages Router
This section walks through the Material UI integration with the Next.js Pages Router, for both Server-side Rendering (SSR) and Static Site Generation (SSG).
Installing the dependencies
Start by ensuring that you already have @mui/material
and next
installed.
Then, run one of the following commands to install the dependencies:
npm install @mui/material-nextjs @emotion/cache @emotion/server
Configuration
Inside the pages/_document.tsx
file:
- Import
documentGetInitialProps
and use it as the Document'sgetInitialProps
. - Import
DocumentHeadTags
and render it inside the<Head>
.
+import {
+ DocumentHeadTags,
+ documentGetInitialProps,
+} from '@mui/material-nextjs/v13-pagesRouter';
// or `v1X-pagesRouter` if you are using Next.js v1X
export default function MyDocument(props) {
return (
<Html lang="en">
<Head>
+ <DocumentHeadTags {...props} />
...
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
);
}
+MyDocument.getInitialProps = async (ctx) => {
+ const finalProps = await documentGetInitialProps(ctx);
+ return finalProps;
+};
Then, inside pages/_app.tsx
, import the AppCacheProvider
component and render it as the root element:
+import { AppCacheProvider } from '@mui/material-nextjs/v13-pagesRouter';
// Or `v1X-pages` if you are using Next.js v1X
export default function MyApp(props) {
return (
+ <AppCacheProvider {...props}>
<Head>
...
</Head>
...
+ </AppCacheProvider>
);
}
Custom cache (optional)
To use a custom Emotion cache, pass it to the emotionCache
property in _document.tsx
:
// pages/_document.tsx
...
MyDocument.getInitialProps = async (ctx) => {
const finalProps = await documentGetInitialProps(ctx, {
+ emotionCache: createCustomCache(),
});
return finalProps;
};
App enhancement (optional)
Pass an array to the plugins
property to enhance the app with additional features, like server-side-rendered styles if you're using JSS and styled-components.
Each plugin must have the following properties:
enhanceApp
: a higher-order component that receives theApp
component and returns a new app component.resolveProps
: a function that receives the initial props and returns a new props object.
When run, enhanceApp
from each plugin is called first, from top to bottom, and then the process is repeated for resolveProps
.
import { ServerStyleSheet } from 'styled-components';
MyDocument.getInitialProps = async (ctx) => {
const jssSheets = new JSSServerStyleSheets();
const styledComponentsSheet = new ServerStyleSheet();
try {
const finalProps = await documentGetInitialProps(ctx, {
emotionCache: createEmotionCache(),
plugins: [
{
// styled-components
enhanceApp: (App) => (props) =>
styledComponentsSheet.collectStyles(<App {...props} />),
resolveProps: async (initialProps) => ({
...initialProps,
styles: [
styledComponentsSheet.getStyleElement(),
...initialProps.styles,
],
}),
},
{
// JSS
enhanceApp: (App) => (props) => jssSheets.collect(<App {...props} />),
resolveProps: async (initialProps) => {
const css = jssSheets.toString();
return {
...initialProps,
styles: [
...initialProps.styles,
<style
id="jss-server-side"
key="jss-server-side"
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{ __html: css }}
/>,
<style id="insertion-point-jss" key="insertion-point-jss" />,
],
};
},
},
],
});
return finalProps;
} finally {
styledComponentsSheet.seal();
}
};
TypeScript
If you are using TypeScript, add DocumentHeadTagsProps
to the Document's props interface:
+import type { DocumentHeadTagsProps } from '@mui/material-nextjs/v13-pagesRouter';
// or `v1X-pagesRouter` if you are using Next.js v1X
+export default function MyDocument(props: DocumentProps & DocumentHeadTagsProps) {
...
}
Theming
In pages/_app.tsx
, create a new theme and pass it to ThemeProvider
:
import * as React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/app';
import { AppCacheProvider } from '@mui/material-nextjs/v13-pagesRouter';
+import { ThemeProvider, createTheme } from '@mui/material/styles';
+import { Roboto } from 'next/font/google';
+const roboto = Roboto({
+ weight: ['300', '400', '500', '700'],
+ subsets: ['latin'],
+ display: 'swap',
+});
+const theme = createTheme({
+ typography: {
+ fontFamily: roboto.style.fontFamily,
+ },
+});
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
return (
<AppCacheProvider {...props}>
<Head>...</Head>
+ <ThemeProvider theme={theme}>
<Component {...pageProps} />
+ </ThemeProvider>
</AppCacheProvider>
);
}
To learn more about theming, check out the Theming guide.
CSS theme variables
If you want to use CSS theme variables, use the extendTheme
and CssVarsProvider
instead:
// pages/_app.tsx
-import { ThemeProvider, createTheme } from '@mui/material/styles';
+import { CssVarsProvider, extendTheme } from '@mui/material/styles';
Learn more about the advantages of CSS theme variables.