はじめに
Material UIはReactのUIコンポーネントライブラリの1つです。名のとおりGoogleのMaterial Designを実装するUIコンポーネントを提供しています(提供されるのは最新のMaterial Design 3ではなくMaterial Design 2です)。
その洗礼された豊富なコンポーネントを手軽に、独自のデザインシステムにカスタマイズしながら利用できる優れたライブラリです。
そんなMaterial UIですが、バージョン5.15.0でNext.jsと統合するためのライブラリとして、@mui/material-nextjs
の提供を開始しました。
この記事では@mui/material-nextjs
を用いたNext.jsのApp Routerとの統合について解説します。
統合
Nextjsの環境準備
npx create-next-app
でNextjsの最新のプロジェクトを作成します。作成のための質問には以下のように答えました。装飾はMaterial UIで行いたいのでTailwind CSSをNoに選択しました。
装飾をMaterial UIをベースに行わせるために、CSSやCSS Modulesで書かれている部分を外していきます。CSSファイルは削除して、tsx
ファイルはそれぞれ以下のように変更します。
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
)
}
export default function Home() {
return <></>
}
Material UIを利用可能に
次に、Material UIに関連するライブラリを導入します。
npm install @mui/material @emotion/react @emotion/styled @mui/material-nextjs @emotion/cache
すでにMaterial UIの環境がある場合は下の2つだけで問題ないです。
npm install @mui/material-nextjs @emotion/cache
パッケージ類の準備は完了なのでlayout.tsx
とpage.tsx
を触っていきます。
まずは、layout.tsx
でbody
以下の要素に対するProviderを設置します。
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'
import { AppRouterCacheProvider } from '@mui/material-nextjs/v14-appRouter';
const inter = Inter({ subsets: ['latin'] })
export const metadata: Metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
export default function RootLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<html lang="en">
<body className={inter.className}>
<AppRouterCacheProvider>
{children}
</AppRouterCacheProvider>
</body>
</html>
)
}
Nextjsのバージョン14以上を利用の方は上記のように、13以上の場合は'@mui/material-nextjs/v13-appRouter'
から同じようにProviderを取得してください。
その後、Material UIを使ったコードをpage.tsx
で利用可能になります。
import { Button, Stack, TextField, Typography } from "@mui/material";
export default function Home() {
return (
<Stack height="100lvh" justifyContent="center" alignItems="center" gap="32px">
<Typography id="login_heading" variant="h1" fontSize="1.5rem">ログインフォーム</Typography>
<Stack component="form" width={560} gap="24px" aria-labelledby="login_heading">
<TextField label="メールアドレス" />
<TextField label="パスワード" />
<Button variant="contained">ログイン</Button>
</Stack>
</Stack>
);
}
出力は以下の通りMaterial UIで装飾されたものです。
これで統合は完了です。
AppRouterCacheProvider
@mui/material-nextjs
を利用してApp RouterにMaterial UIを統合するためにはAppRouterCacheProvider
をルートに設置するだけでした。
AppRouterCacheProvider
はReactによって生成されたスタイルを@emotion/cache
を利用して収集して、useServerInsertedHTML
でhead
に追加しています。
Material UIで使われているEmotionについての解説はありませんが、Nextjsのドキュメントではstyled-jsx
やstyled-component
などのCSS in JSについてuseServerInsertedHTML
を用いて同様の処理が書かれています。
オプション
AppRouterCacheProvider
にはchildren
の他に2つのpropsをとります。
1つ目はemotion/cache
のcreaeCache
に渡すための設定に加えてenableCssLayer
をキーとした真偽値を任意のオブジェクトとしてoptions
という名前で持ちます。
creaeCache
に渡すための設定はCSP(Content Security Policy)
が有効な時に使われるnonce
属性や、前処理中にStylisによって実行されるプラグインを渡すstylisPlugins
、クラス名のプレフィックスとして利用されるkey
、スタイルタグを挿入するDOMを指定するcontainer
などを渡します(参考)。
enableCssLayer
は真偽値を値として取り、true
にした場合は生成したスタイルを@layer mui
で囲むようになります。これによってEmotionを利用せずに、Tailwind CSSやCSS Modulesなどを用いてMaterial UIのスタイリングを上書きすることが可能となります。@layer
は詳細度をより細かく制御するためのアットルールです。
2つ目はCacheProvider
です。 デフォルトではemotion/react
のCacheProvider
が利用されていますが、他のEmotionに対するキャッシュプロバイダを渡せます。
さいごに
NextjsのApp RouterにMaterial UIを統合させる方法を紹介しました。Material UIはこれまでApp Routerで利用するためには例にあるように複雑なコンポーネントを手前で組み込んで利用する必要がありましたが、@mui/material-nextjs
の登場で解決しました。
未だ、ほとんどのコンポーネントは'use client'
が貼られており、クライアントコンポーネントとして扱うことになってしまいますが、これまでより少し使いやすくなったのではないかなと思います。