Files
react-test/docs/data/material/integrations/nextjs/nextjs.md

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

432 lines
13 KiB
Markdown
Raw Normal View History

2025-12-12 14:26:25 +09:00
# Next.js integration
<p class="description">Learn how to use Material UI with Next.js.</p>
## App Router
This section walks through the Material UI integration with the Next.js [App Router](https://nextjs.org/docs/app), an evolution of the [Pages Router](#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:
<codeblock storageKey="package-manager">
```bash npm
npm install @mui/material-nextjs @emotion/cache
```
```bash pnpm
pnpm add @mui/material-nextjs @emotion/cache
```
```bash yarn
yarn add @mui/material-nextjs @emotion/cache
```
</codeblock>
### Configuration
Inside `app/layout.tsx`, import the `AppRouterCacheProvider` and wrap all elements under the `<body>` with it:
```diff title="app/layout.tsx"
+import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-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>
);
}
```
:::info
The `AppRouterCacheProvider` component is responsible for collecting the CSS generated by MUI System on the server, as Next.js is streaming chunks of the .html page to the client.
While it's not required to use the `AppRouterCacheProvider` component, it's recommended to use it to ensure that the styles are appended to the `<head>` and not rendering in the `<body>`.
See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153 for why it's better.
:::
#### Custom cache (optional)
Use the `options` prop to override the default [cache options](https://emotion.sh/docs/@emotion/cache#options)—for example, the code snippet below shows how to change the CSS key to `css` (the default is `mui`):
```diff
<AppRouterCacheProvider
+ options={{ key: 'css' }}
>
{children}
</AppRouterCacheProvider>
```
### Font optimization
To integrate [Next.js font optimization](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) with Material UI, create a new file with the `'use client';` directive.
Then create a theme using `var(--font-roboto)` as a value for the `typography.fontFamily` field.
```js title="src/theme.ts"
'use client';
import { createTheme } from '@mui/material/styles';
const theme = createTheme({
typography: {
fontFamily: 'var(--font-roboto)',
},
});
export default theme;
```
Finally, in `src/app/layout.tsx`, pass the theme to the `ThemeProvider`:
```diff title="app/layout.tsx"
import { AppRouterCacheProvider } from '@mui/material-nextjs/v15-appRouter';
+import { Roboto } from 'next/font/google';
+import { ThemeProvider } from '@mui/material/styles';
+import theme from '../theme';
+const roboto = Roboto({
+ weight: ['300', '400', '500', '700'],
+ subsets: ['latin'],
+ display: 'swap',
+ variable: '--font-roboto',
+});
export default function RootLayout(props) {
const { children } = props;
return (
+ <html lang="en" className={roboto.variable}>
<body>
<AppRouterCacheProvider>
+ <ThemeProvider theme={theme}>
{children}
+ </ThemeProvider>
</AppRouterCacheProvider>
</body>
</html>
);
}
```
To learn more about theming, check out the [theming guide](/material-ui/customization/theming/) page.
### CSS theme variables
To use [CSS theme variables](/material-ui/customization/css-theme-variables/overview/), enable the `cssVariables` flag:
```diff title="src/theme.ts"
'use client';
const theme = createTheme({
+ cssVariables: true,
});
```
Learn more about [the advantages of CSS theme variables](/material-ui/customization/css-theme-variables/overview/#advantages) and how to [prevent SSR flickering](/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering).
### 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:
```js
<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](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/At-rules/@layer).
### Next.js v16 Client Component restriction
If you encounter `Functions cannot be passed directly to Client Components` error from passing Next.js Link to Material UI `component` prop, you need to create a wrapper component with `use client` directive like the following:
```tsx title="src/components/Link.tsx"
'use client';
import Link, { LinkProps } from 'next/link';
export default Link;
```
Then, replace the Next.js Link with the wrapper component:
```diff title="src/app/page.tsx"
- import Link from 'next/link';
+ import Link from '../components/Link';
...
<Button component={Link} href="/about" variant="contained">
Go to About Page
</Button>
```
## Pages Router
This section walks through the Material UI integration with the Next.js [Pages Router](https://nextjs.org/docs/pages/building-your-application), for both [Server-side Rendering](https://nextjs.org/docs/pages/building-your-application/rendering/server-side-rendering) (SSR) and [Static Site Generation](https://nextjs.org/docs/pages/building-your-application/rendering/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:
<codeblock storageKey="package-manager">
```bash npm
npm install @mui/material-nextjs @emotion/cache @emotion/server
```
```bash pnpm
pnpm add @mui/material-nextjs @emotion/cache @emotion/server
```
```bash yarn
yarn add @mui/material-nextjs @emotion/cache @emotion/server
```
</codeblock>
### Configuration
Inside the `pages/_document.tsx` file:
- Import `documentGetInitialProps` and use it as the Document's `getInitialProps`.
- Import `DocumentHeadTags` and render it inside the `<Head>`.
```diff title="pages/_document.tsx"
+import {
+ DocumentHeadTags,
+ documentGetInitialProps,
+} from '@mui/material-nextjs/v15-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:
```diff title="pages/_app.tsx"
+import { AppCacheProvider } from '@mui/material-nextjs/v15-pagesRouter';
// Or `v1X-pages` if you are using Next.js v1X
export default function MyApp(props) {
return (
+ <AppCacheProvider {...props}>
<Head>
...
</Head>
...
+ </AppCacheProvider>
);
}
```
:::info
The `AppCacheProvider` component is responsible for collecting the CSS generated by MUI System on the server, as Next.js is rendering the .html page to the client.
While it's not required to use the `AppCacheProvider` component, it's recommended to use it to ensure that the styles are appended to the `<head>` and not rendering in the `<body>`.
See https://github.com/mui/material-ui/issues/26561#issuecomment-855286153 for why it's better.
:::
#### Custom cache (optional)
To use a custom [Emotion cache](https://emotion.sh/docs/@emotion/cache), pass it to the `emotionCache` property in `_document.tsx`:
```diff title="pages/_document.tsx"
...
MyDocument.getInitialProps = async (ctx) => {
const finalProps = await documentGetInitialProps(ctx, {
+ emotionCache: createCustomCache(),
});
return finalProps;
};
```
#### Cascade layers (optional)
To enable [cascade layers](https://developer.mozilla.org/en-US/docs/Learn_web_development/Core/Styling_basics/Cascade_layers) (`@layer`), create a new cache with `enableCssLayer: true` and pass it to the `emotionCache` property in both `_document.tsx` and `_app.tsx`:
```diff title="pages/_document.tsx"
+import { createEmotionCache } from '@mui/material-nextjs/v15-pagesRouter';
...
MyDocument.getInitialProps = async (ctx) => {
const finalProps = await documentGetInitialProps(ctx, {
+ emotionCache: createEmotionCache({ enableCssLayer: true }),
});
return finalProps;
};
```
```diff title="pages/_app.tsx"
+import { createEmotionCache } from '@mui/material-nextjs/v15-pagesRouter';
...
const clientCache = createEmotionCache({ enableCssLayer: true });
+ export default function MyApp({ emotionCache = clientCache }) {
return (
+ <AppCacheProvider emotionCache={emotionCache}>
<Head>
...
</Head>
...
</AppCacheProvider>
);
}
```
#### 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 the `App` 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`.
```js
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:
```diff
+import type { DocumentHeadTagsProps } from '@mui/material-nextjs/v15-pagesRouter';
// or `v1X-pagesRouter` if you are using Next.js v1X
+export default function MyDocument(props: DocumentProps & DocumentHeadTagsProps) {
...
}
```
### Font optimization
To integrate [Next.js font optimization](https://nextjs.org/docs/pages/building-your-application/optimizing/fonts) with Material UI, open `pages/_app.tsx` and create a theme using `var(--font-roboto)` as a value for the `typography.fontFamily` field.
```diff title="pages/_app.tsx"
import * as React from 'react';
import Head from 'next/head';
import { AppProps } from 'next/app';
import { AppCacheProvider } from '@mui/material-nextjs/v15-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',
+ variable: '--font-roboto',
+});
+const theme = createTheme({
+ typography: {
+ fontFamily: 'var(--font-roboto)',
+ },
+});
export default function MyApp(props: AppProps) {
const { Component, pageProps } = props;
return (
<AppCacheProvider {...props}>
<Head>...</Head>
+ <ThemeProvider theme={theme}>
+ <main className={roboto.variable}>
<Component {...pageProps} />
+ </main>
+ </ThemeProvider>
</AppCacheProvider>
);
}
```
To learn more about theming, check out the [Theming guide](/material-ui/customization/theming/).
### CSS theme variables
To use [CSS theme variables](/material-ui/customization/css-theme-variables/overview/), enable the `cssVariables` flag:
```diff title="src/theme.ts"
'use client';
const theme = createTheme({
+ cssVariables: true,
});
```
Learn more about [the advantages of CSS theme variables](/material-ui/customization/css-theme-variables/overview/#advantages) and how to [prevent SSR flickering](/material-ui/customization/css-theme-variables/configuration/#preventing-ssr-flickering).