結論

MUIは、Material Designを実装したReactの部品集「Material UI」と、その開発元です。本体はMITライセンスで無料です。

この記事でわかること

  • Vite+Reactに入れる5手順とビルドの実測値
  • Next.jsで設定を外すと起きる問題4つの実測
  • エラー原文12件(v7の書き方・Next.js等)

2026年10月23日更新|@mui/material 9.5.0・Vite 8.3.5・Next.js 16.4.2で確認

MUI の部品は、テーマ(色・文字・余白の決まり)を読み込み、Emotion というライブラリが CSS を作ってページに差し込む仕組みで描かれます。

flowchart TD
    A[createTheme で<br>色・文字・余白を決める] --> B[ThemeProvider で<br>アプリ全体に渡す]
    B --> C[Button などの<br>部品を import して置く]
    C --> D[sx か styled で<br>見た目を足す]
    D --> E[Emotion が CSS を作り<br>style タグに入れる]

よく使う操作を先にまとめます。

やりたいこと 書き方 補足
入れる npm install @mui/material @emotion/react @emotion/styled React 17〜19 に対応
アイコンを使う npm install @mui/icons-material 1つずつパスで import
色を変える createTheme({ palette: { primary: { main: '#0b5cad' } } }) ThemeProvider で渡す
ダークモード createTheme({ colorSchemes: { dark: true } }) 切り替えは useColorScheme
余白・色を足す sx={{ p: 2, bgcolor: 'primary.main' }} p: 2 は 16px
横に並べる <Stack direction="row" spacing={1}> 1方向のレイアウト
列で区切る <Grid size={{ xs: 12, md: 4 }}> v7 以降は item を書かない
表を出す @mui/x-data-grid の DataGrid 無料版は1ページ100行まで
Next.js で使う AppRouterCacheProvider で包む @mui/material-nextjs

確認環境:Ubuntu 24.04.4・Node.js 22.22.2・npm 10.9.7。create-vite 9.3.1 で作った React+TypeScript のプロジェクト(Vite 8.3.5・React 19.3.1・TypeScript 6.0.3)に、@mui/material 9.5.0・@emotion/react 11.14.0・@emotion/styled 11.14.1・@mui/icons-material 9.5.0・@mui/x-data-grid 9.16.0・@fontsource/roboto 5.3.0 を入れ、npm run build と vite preview で動かしました。表示・色・レイアウト・ダイアログ・ダークモードは Chromium 141(playwright 1.56.0)で、幅 390px と 1280px で測りました。Next.js は 16.4.2 の App Router に @mui/material-nextjs 9.5.0 を入れて next build・next start で確かめ、移行は @mui/codemod 9.4.0 を実行しました。エラーはすべて同じプロジェクトでわざと起こした原文です。料金・ライセンス・Material Design の対応範囲・Date Pickers・Tailwind CSS との併用は mui.com の公式ドキュメントと料金ページ、shadcn/ui と Chakra UI は各公式のインストールのページと npm のパッケージ情報で確かめました(確認日 2026年10月23日)。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「MUI(Material UI)とは|使い方・テーマ・Gridをv9の実例で解説」

MUIとは(読み方・Material UIとの関係・無料か)

この節では、MUI が何を指す言葉で、何ができて、お金がかかるのかが分かります。

MUI は会社(とブランド)の名前で、その中心の製品が React の部品集「Material UI」です。 公式ドキュメントは Material UI を「Google の Material Design を実装した、オープンソースの React の部品ライブラリ」と説明しています。ボタン・入力欄・ダイアログ・表・メニューなどを、import して置くだけで、Material Design の見た目とキーボード操作つきで使えます。

読み方は「エム・ユー・アイ」です。2021年9月16日の公式ブログ(Material-UI is now MUI)で、名前の意味は「Material to build UIs」、発音は /ɛm juː aɪ/ と書かれています。このとき、以前の「Material-UI」という名前と @material-ui の npm のスコープから、今の「MUI」と @mui に変わりました。

無料か・商用で使えるか

Material UI 本体(@mui/material)は MIT ライセンスで、無料で商用のアプリにも使えます。 npm の表示も MIT です。料金がかかるのは、表やグラフなどの高機能な部品を集めた MUI X の Pro・Premium だけです(無料と有料の範囲は「MUI X」の節)。

製品 npm のパッケージ 料金(2026年10月23日時点)
Material UI @mui/material 無料(MIT)
MUI のアイコン @mui/icons-material 無料(MIT)
MUI X Community @mui/x-data-grid など 無料(MIT)
MUI X Pro @mui/x-data-grid-pro など 開発者1人あたり年 299 ドル
MUI X Premium @mui/x-data-grid-premium など 開発者1人あたり年 599 ドル

Material Design 3(Material You)に対応しているか

2026年10月23日時点の公式ドキュメントは「Material UI supports Material Design 2」と書いています。 Android などで使われている Material Design 3 の見た目そのものではありません。見た目はテーマで大きく変えられるので、Material Design らしさを消して自社のデザインに合わせる使い方も多くあります。

MUIの製品の種類(Material UI・MUI X・Base UI)

この節では、「MUI」と書かれたときに指していることがある製品を見分けられます。

1Material UI

Material Design の見た目の部品集。@mui/material。この記事の主役。無料(MIT)。

2MUI X

DataGrid(表)・Date Pickers(日付)・Charts(グラフ)・Tree View・Scheduler。無料版と有料版がある。

3Base UI

見た目を持たない(ヘッドレスな)部品。@base-ui/react。MUI の今後の土台で、shadcn/ui の既定の土台でもある。

4MUI System

sx・Box・Stack などのスタイルの仕組み。@mui/system。Material UI の中で使われる。

ほかに Joy UI(Material Design ではない見た目の部品集)と Pigment CSS(ビルド時に CSS を作る仕組み)がありますが、2026年1月1日の公式ブログは、どちらも開発を止めている(on hold)と書いています。v9 では Joy UI のコードとドキュメントがリポジトリから外されました。

バージョンの流れ(v8は無い)

版 最初の公開(npm) 主なこと
v5 2021年9月16日 @material-ui/core から @mui/material へ
v6 2024年8月27日 latest-v6 は 6.5.0
v7 2025年3月26日 latest-v7 は 7.3.11
v9 2026年4月7日 v8 を飛ばし MUI X と版をそろえた

Material UI に v8 はありません。 公式ブログ(Introducing Material UI and MUI X v9、2026年4月8日)は、MUI X v9 と同じ番号にそろえるために v7 から v9 へ進んだと説明しています。2026年10月23日時点の npm の最新は 9.5.0(2026年10月9日公開)で、next のタグには 10.0.0-alpha.0 が出ています。v5 の時代の解説で @material-ui/core と書かれているものは、@mui/material に読み替えます。

MUIのインストール方法(npm・Vite)

この節では、入れるパッケージと、入れた後に最初に書く3つのことが分かります。

入れるパッケージ

npm install @mui/material @emotion/react @emotion/styled

@emotion/react と @emotion/styled は、MUI が CSS を作るときに使うライブラリで、@mui/material の peer dependency(自分で入れる依存)です。@mui/material 9.5.0 の peer dependency は次のとおりでした(npm の表示)。

react: ^17.0.0 || ^18.0.0 || ^19.0.0
react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0
@emotion/react: ^11.5.0
@emotion/styled: ^11.3.0

公式のインストールのページは、React 18 以前では react-is を React と同じ版で入れ、package.json の overrides で固定する手順を案内しています。Emotion の代わりに styled-components を使う方法(@mui/styled-engine-sc)もありますが、公式は「サーバーで描画する Material UI のプロジェクトとは互換性がない」と書き、SSR では Emotion を強くすすめています。

入れた後にすること

1

Vite で React のプロジェクトを作る

npm create vite@latest app -- --template react-ts で作り、npm install。

create-vite 9.3.1

2

MUI と Emotion を入れる

上の npm install の3つ。アイコンを使うなら @mui/icons-material も。

MUI 9.5.0

3

フォントを読み込む

MUI の既定の書体は Roboto。@fontsource/roboto を入れて、使う太さの CSS を import する。

300・400・500・700

4

テーマを作って渡す

createTheme で作り、ThemeProvider でアプリを包む。CssBaseline でブラウザごとの差をならす。

main.tsx

5

部品を import して置く

import Button from '@mui/material/Button' の形で1つずつ。

App.tsx

npm install @fontsource/roboto @mui/icons-material

src/main.tsx はこうしました。CssBaseline は、余白の初期値をそろえ、背景色と文字色をテーマの値にする部品です。

// src/main.tsx
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import '@fontsource/roboto/400.css'
import '@fontsource/roboto/500.css'
import CssBaseline from '@mui/material/CssBaseline'
import { ThemeProvider } from '@mui/material/styles'
import { theme } from './theme'
import App from './App.tsx'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <ThemeProvider theme={theme}>
      <CssBaseline />
      <App />
    </ThemeProvider>
  </StrictMode>,
)

Roboto には日本語の字形が無いので、日本語は次の書体に回ります。この記事のテーマでは fontFamily を Roboto, "Noto Sans JP", sans-serif にしました(テーマの節)。Vite のプロジェクトの作り方は、関連記事「React環境構築をViteで行う手順|create viteの使い方」で扱っています。

公式のページには CDN(<script> で読み込む)の例もありますが、ライブラリ全体を読み込むため、公式は「本番での使用はすすめない」と書いています。

MUIの使い方(Vite+Reactでビルドした実例)

この節では、ボタン・カード・入力欄・ダイアログ・表を1画面に置いたアプリを作り、ビルドしてブラウザで測った結果が分かります。

画面のコード

部品を1つずつ import して並べました(抜粋。全体は約150行)。

// src/App.tsx(抜粋)
import Stack from '@mui/material/Stack'
import Grid from '@mui/material/Grid'
import Button from '@mui/material/Button'
import TextField from '@mui/material/TextField'
import Card from '@mui/material/Card'
import CardContent from '@mui/material/CardContent'
import Typography from '@mui/material/Typography'
import Chip from '@mui/material/Chip'

export default function App() {
  const [name, setName] = useState('')
  const error = name.length > 0 && name.length < 3
  return (
    <Stack spacing={3}>
      <Stack direction="row" spacing={1} useFlexGap sx={{ flexWrap: 'wrap' }}>
        <Button variant="contained">保存</Button>
        <Button variant="outlined">キャンセル</Button>
        <Button variant="text">詳細</Button>
        <Button variant="contained" color="secondary">送信</Button>
        <Button variant="contained" color="error">削除</Button>
        <Button variant="contained" disabled>無効</Button>
      </Stack>

      <Grid container spacing={2}>
        {[1, 2, 3].map((n) => (
          <Grid key={n} size={{ xs: 12, md: 4 }}>
            <Card variant="outlined">
              <CardContent>
                <Typography variant="h6" component="h2">カード {n}</Typography>
                <Chip label="新着" color="primary" size="small" sx={{ mt: 1 }} />
              </CardContent>
            </Card>
          </Grid>
        ))}
      </Grid>

      <TextField
        label="ユーザー名"
        value={name}
        onChange={(e) => setName(e.target.value)}
        error={error}
        helperText={error ? '3文字以上で入力します' : '半角英数字'}
        slotProps={{ htmlInput: { maxLength: 20 } }}
      />
    </Stack>
  )
}

variant は見た目の種類(contained は塗りつぶし、outlined は枠線、text は文字だけ)、color はテーマのどの色を使うかです。入力欄の <input> 要素に属性を渡すときは、v9 では slotProps={{ htmlInput: { … } }} と書きます(以前の inputProps は v9 で外されました)。

ビルドの結果

> app@0.0.0 build
> tsc -b && vite build

vite v8.3.5 building client environment for production...
transforming...
✓ 1290 modules transformed.
rendering chunks...
computing gzip size...
dist/assets/index-RdD2w5nh.css     23.28 kB │ gzip:  11.89 kB
dist/assets/index-CkJaa3qr.js   1,023.05 kB │ gzip: 309.28 kB

(!) Some chunks are larger than 500 kB after minification. Consider:
- Using dynamic import() to code-split the application
✓ built in 768ms

(Roboto の woff・woff2 のファイル32個の行は省きました。)

309kBJS の大きさ(gzip 後)DataGrid を含む。Button だけなら104kB
232個テーマから作られた CSS 変数--mui-palette-primary-main など
0.77秒vite build の時間1,290モジュール。tsc の型チェックは別

DataGrid を入れると JS が 500kB を超え、Vite が警告を出しました。 警告であってビルドは成功しています。表のページだけを React.lazy と import() で分けると、最初に読み込む量を減らせます(Vite の警告文の1つ目の案)。部品ごとの大きさは「アイコン」の節の表に載せます。

ブラウザで測った見た目と動き

vite preview で開いた画面を Chromium で調べた結果です。

btn-contained: bg=rgb(11, 92, 173) color=rgb(255, 255, 255) h=36.5 radius=8px
btn-outlined: bg=rgba(0, 0, 0, 0) color=rgb(11, 92, 173) h=36.5 radius=8px
btn-text: bg=rgba(0, 0, 0, 0) color=rgb(11, 92, 173) h=36.5 radius=8px
btn-secondary: bg=rgb(230, 81, 0) color=rgb(255, 255, 255) h=36.5 radius=8px
btn-error: bg=rgb(211, 47, 47) color=rgb(255, 255, 255) h=36.5 radius=8px
class: MuiButtonBase-root MuiButton-root MuiButton-contained MuiButton-sizeMedium MuiButton-colorPrimary MuiButton-disableElevation css-t4sc2b
textfield "ab": aria-invalid=true helper=3文字以上で入力します
textfield "abcd": aria-invalid=false

ボタンの色はテーマで決めた #0b5cad(rgb(11, 92, 173))と #e65100、error は MUI の既定の #d32f2f でした。部品には MuiButton-contained のような決まった名前のクラスと、Emotion が作った css-t4sc2b のようなクラスが付きます。CSS で上書きするときは、決まった名前のクラス(.MuiButton-contained など)を使います。 css- の後ろの文字は中身から作られるので、スタイルが変わると変わります。

ダイアログと通知(Snackbar)を開いたときの動きです。

dialog: role=dialog labelledby=確認 portalParentIsBody=true active=MuiPaper-root rootAriaHidden=true
after Esc dialogs: 0 focus: ダイアログを開く
snackbar: 保存しました role=alert

ダイアログは body の直下に描かれ(ポータル)、開くとフォーカスがダイアログの中へ移り、後ろの #root には aria-hidden="true" が付きました。Esc で閉じると、フォーカスは「ダイアログを開く」ボタンに戻りました。Snackbar の中身は role="alert" なので、スクリーンリーダーにも読まれます。

MUIのコンポーネント早見表

この節では、よく使う部品の名前と用途を引けます。名前は公式の「All components」のページ(2026年10月23日時点)の分類に合わせました。

分類 主な部品(import する名前) 使う場面
入力 Button・TextField・Select・Checkbox・Radio・Switch・Slider・Autocomplete・ToggleButton・Rating フォーム・操作
表示 Typography・Avatar・Badge・Chip・Divider・List・Table・Tooltip 文字・一覧・ラベル
結果を伝える Alert・Dialog・Snackbar・Backdrop・CircularProgress・LinearProgress・Skeleton 確認・通知・読み込み中
面 Card・Paper・Accordion・AppBar 区切り・ヘッダー
移動 Tabs・Drawer・Menu・Breadcrumbs・Pagination・Stepper・Link・BottomNavigation 画面の切り替え
レイアウト Box・Container・Grid・Stack・ImageList 並べる・幅をそろえる
道具 CssBaseline・Modal・Popover・Popper・Portal・useMediaQuery 部品の土台
Lab(試験中) Masonry・Timeline(@mui/lab) 版が上がると変わることがある

v9 で増えた NumberField(数値の入力)と Menubar は、@mui/material の中にはありません。 手元の 9.5.0 にもそのフォルダは無く、公式の NumberField のページは「Material UI does not include a number field component out of the box」と書いています。@base-ui/react を入れ、ドキュメントのデモのコードを自分のプロジェクトにコピーして使う形です。

Alert の severity は error・warning・info・success の4種類、Button の variant は text・outlined・contained の3種類、color は primary・secondary・success・error・info・warning・inherit です(型のエラーに出た一覧。エラーの節)。

MUIのテーマのカスタマイズ(createTheme・色・フォント・日本語)

この節では、部品のコードを変えずに色・角丸・文字・既定の props を変える方法と、表示を日本語にする方法が、手元で効いた設定で分かります。

テーマは「色・文字・余白・角丸・部品ごとの既定値」を1つにまとめたオブジェクトです。 createTheme で作り、ThemeProvider で渡すと、その下の部品が全部その値を使います。手元のアプリのテーマです。

// src/theme.ts
import { createTheme } from '@mui/material/styles'
import { jaJP } from '@mui/material/locale'
import { jaJP as dataGridJaJP } from '@mui/x-data-grid/locales'

export const theme = createTheme(
  {
    cssVariables: { colorSchemeSelector: 'class' },
    colorSchemes: {
      light: { palette: { primary: { main: '#0b5cad' }, secondary: { main: '#e65100' } } },
      dark: { palette: { primary: { main: '#90caf9' } } },
    },
    shape: { borderRadius: 8 },
    typography: {
      fontFamily: ['Roboto', '"Noto Sans JP"', 'sans-serif'].join(','),
      button: { textTransform: 'none' },
    },
    components: {
      MuiButton: { defaultProps: { disableElevation: true } },
    },
  },
  jaJP,
  dataGridJaJP,
)
設定 何を変えたか 測った結果
palette.primary.main 主な色 ボタンの背景が rgb(11, 92, 173)
shape.borderRadius 角丸の基準(既定は4) ボタンの角が 8px
typography.fontFamily 書体 body が Roboto, "Noto Sans JP", sans-serif
typography.button.textTransform ボタンの文字を大文字にしない 英字が入力どおりに出る
components.MuiButton.defaultProps 全ボタンの既定の props クラスに MuiButton-disableElevation
cssVariables 値を CSS 変数で出す --mui-* が232個
2つ目以降の引数 jaJP 部品の文言を日本語に 表の下が「ページあたりの行数:」

primary.main だけを書くと、light・dark・contrastText(上に載せる文字の色)は MUI が計算します。#0b5cad の上の文字は白(rgb(255, 255, 255))になりました。

日本語にする(ロケール)

createTheme の2つ目以降の引数にロケールを渡すと、部品が持っている文言が変わります。公式のローカライズのページは createTheme(テーマ, zhCN) の形で説明していて、日本語は jaJP です。DataGrid などの MUI X の部品は自分のロケール(@mui/x-data-grid/locales)を持っているので、それも渡します。渡した後の DataGrid の下の部分の文言とボタンのラベルです。

ページあたりの行数: | 5 | 1–5 of 30
前のページへ | 次のページへ

「1–5 of 30」の部分は、jaJP の訳でも of のままでした(ロケールのファイルの paginationDisplayedRows がこの形です)。変えたいときは DataGrid の localeText で上書きします。

部品の見た目をテーマで変える(styleOverrides)

components.MuiButton には defaultProps(既定の props)のほかに styleOverrides(スタイルの上書き)を書けます。特定の部品の見た目をアプリ全体で変えるときは、1つずつ sx を付けるよりここに書くほうが、書き忘れが起きにくくなります。

components: {
  MuiButton: {
    defaultProps: { disableElevation: true },
    styleOverrides: { root: { borderRadius: 999 } },
  },
},

MUIのダークモードの設定(colorSchemes・useColorScheme)

この節では、ライトとダークを切り替え、選んだモードを覚えさせる書き方が、切り替えた実物で分かります。

v9 では createTheme に colorSchemes: { dark: true } を書くと、ライトとダークの両方の色が作られ、既定ではOSの設定(system)に従います。 切り替えは useColorScheme で行います。

import { useColorScheme } from '@mui/material/styles'
import ToggleButton from '@mui/material/ToggleButton'
import ToggleButtonGroup from '@mui/material/ToggleButtonGroup'

function ModeSwitch() {
  const { mode, setMode } = useColorScheme()
  if (!mode) return null // 最初の描画では undefined
  return (
    <ToggleButtonGroup size="small" exclusive value={mode} onChange={(_, v) => v && setMode(v)}>
      <ToggleButton value="light">ライト</ToggleButton>
      <ToggleButton value="system">システム</ToggleButton>
      <ToggleButton value="dark">ダーク</ToggleButton>
    </ToggleButtonGroup>
  )
}

公式のダークモードのページは、mode は「最初の描画では常に undefined」と書いています。そのため、上の例では mode が無いうちは何も描きません。ダークを押してからページを読み直した結果です。

dark: html.class=dark bodyBg=rgb(18, 18, 18) contained=rgb(144, 202, 249)/rgba(0, 0, 0, 0.87) ls={"mui-mode":"dark"}
after reload html.class= dark

選んだモードは localStorage の mui-mode に保存され、読み直してもダークのままでした。colorSchemeSelector: 'class' にしたので、<html> に dark クラスが付き、ボタンはダーク用に決めた #90caf9、背景は rgb(18, 18, 18) になりました。

書き方 動き 向いている場面
palette: { mode: 'dark' } 常にダーク 切り替えが要らない
colorSchemes: { dark: true } OS に従う+切り替え可 多くのアプリ
+cssVariables: { colorSchemeSelector: 'class' } <html class="dark"> で切り替え Tailwind の dark: と合わせたい
+InitColorSchemeScript 読み込み直後からダーク Next.js などのサーバー描画

サーバーで描画するアプリでは、最初の一瞬ライトで表示されることがあります。 防ぎ方は Next.js の節に、実測した結果つきで載せます。CSS だけでダークモードを作る方法は、関連記事「CSS変数(カスタムプロパティ)の使い方|コピペ実例とダークモード切替」で扱っています。

sxとstyledの違いと使い分け

この節では、部品に見た目を足す2つの方法の違いと、sx の値が何ピクセルになるかが、測った値で分かります。

カードの余白と背景色を変えたいとき

sxその場所の1つだけに書く。sx={{ p: 2, bgcolor: 'primary.main' }}。テーマの値を短い名前で使え、画面幅ごとの値も書ける
→
styled名前のある部品を作り、何度も使う。const Panel = styled('section')(…)。props で見た目を変える部品に向く

どちらも Emotion が CSS を作り、クラスとして付く。1回きりなら sx、繰り返すなら styled

sxの書き方と、実際の値

<Box
  sx={{
    p: 2,                              // padding: theme.spacing(2)
    m: { xs: 1, md: 4 },               // 画面幅で変える
    bgcolor: 'primary.main',           // テーマの色
    color: 'primary.contrastText',
    borderRadius: 1,                   // theme.shape.borderRadius × 1
    width: { xs: '100%', md: '50%' },
  }}
>
  sx で余白・色・幅を指定した Box
</Box>

幅 390px と 1280px で測った値です。

390px:  padding=16px width=358.0 bg=rgb(11, 92, 173) cls=MuiBox-root css-1mfry8l
1280px: padding=16px width=576.0 bg=rgb(11, 92, 173) cls=MuiBox-root css-1mfry8l

p: 2 は 2×8px で 16px、width は 390px では 100%(358px)、1280px では 50%(576px)になりました。sx の数値は、余白(p・m など)は theme.spacing(既定 8px)の倍数、borderRadius は theme.shape.borderRadius の倍数、width などは 0〜1 の値なら割合になります。 画面幅の区切り(ブレークポイント)の既定値は次のとおりです(公式ドキュメント)。

名前 この幅以上 よくある端末
xs 0px スマホ
sm 600px 大きめのスマホ・小さいタブレット
md 900px タブレット・小さいノート PC
lg 1200px PC
xl 1536px 大きい画面

この測定では、同じ Box に書いた m: { xs: 1, md: 4 } が効かず、上の余白は 24px でした。理由は次の Stack の節で説明します。

styledの書き方

import { styled } from '@mui/material/styles'

const Panel = styled('section')(({ theme }) => ({
  padding: theme.spacing(2),
  borderRadius: theme.shape.borderRadius,
  border: `1px solid ${theme.palette.divider}`,
}))

// 使うとき
<Panel>…</Panel>

theme を受け取れるので、sx と同じテーマの値を使えます。どちらで書いても最後は Emotion のクラス(css-…)になり、Vite でビルドした画面には Emotion の <style> タグが5つありました(data-emotion が css-global と css)。

公式の sx のページは、値がたくさん変わる(描画ごとに違う値を渡す)場合は、sx のオブジェクトを変えるより CSS 変数をインラインで渡す方法をすすめています。sx は書くたびに CSS を作るので、何千行もある一覧の各行に違う sx を付けるような使い方では、性能に影響が出ることがあります。

GridとStackでレイアウトを組む

この節では、Grid(列で区切る)と Stack(一方向に並べる)の使い分けと、画面幅による並び方の違いが、測った座標で分かります。

Grid(12列で区切る)

v9 の Grid は、<Grid container> の中に <Grid size={…}> を置き、12列のうち何列を使うかを size で書きます。 item は書きません。

<Grid container spacing={2}>
  {[1, 2, 3].map((n) => (
    <Grid key={n} size={{ xs: 12, md: 4 }}>
      <Card variant="outlined">…</Card>
    </Grid>
  ))}
</Grid>
幅 カード1 カード2 カード3
390px x=16・y=219・幅358 x=16・y=341・幅358 x=16・y=463・幅358
1280px x=64・y=183・幅373.3 x=453・y=183・幅373.3 x=843・y=183・幅373.3

390px では xs: 12(12列ぜんぶ)で縦に並び、1280px では md: 4 で3つが横に並びました。1280px の幅 373.3px は、Container(最大 1200px、左右の余白 24px)の中の 1152px から、すき間 16px(spacing={2})2つを引いて3で割った値です。

Grid の props 意味 例
size 使う列の数 size={6}、size={{ xs: 12, md: 6 }}
size="auto" 中身の幅だけ ボタンの列
size="grow" 残りを分け合う 可変の真ん中の列
offset 右へずらす列の数 offset={{ md: 2 }}
spacing・rowSpacing・columnSpacing すき間(8px の倍数) spacing={2}
columns 全体の列の数(既定 12) columns={16}

公式の Grid のページは、direction="column" は使えない(縦に並べるなら Grid の中に Stack を置く)、行をまたぐ配置や自動の配置はできない(それには CSS Grid を使う)と書いています。

Stack(一方向に並べる)と、子の margin が効かない理由

Stack は、子を縦(既定)か横(direction="row")に、すき間をあけて並べます。既定の Stack は、すき間を「子の margin」で作るので、子に付けた margin が上書きされます。 2つのボタンにどちらも sx={{ m: 4 }}(32px)を付けて測った結果です。

Stack spacing={3}:            s1 margin=0px/0px/0px/0px  s2 margin=24px/0px/0px/0px  gap=normal
Stack spacing={3} useFlexGap: f1 margin=32px/32px/32px/32px  f2 margin=32px/32px/32px/32px  gap=24px

既定の Stack

すき間は子の margin-top(24px)

子の m: 4 は消える

折り返すとすき間がずれる

useFlexGap を付けた Stack

すき間は CSS の gap(24px)

子の m: 4 がそのまま効く

flexWrap: 'wrap' でもそろう

公式の Stack のページも「子の margin のカスタマイズは既定では対応しない」とし、useFlexGap を付けて CSS の flexbox の gap に切り替える方法を案内しています。sx の節の Box の m が効かなかったのも、この Box が Stack spacing={3} の子だったためです。ボタンを横に並べて折り返す場合も、useFlexGap を付けると行と行のすき間がそろいます。

状況 使うもの
ボタン・アイコンを横に並べる Stack direction="row"
フォームの項目を縦に並べる Stack spacing={2}
カードを画面幅で2列・3列にする Grid container+size
サイドバーと本文の幅を決める Grid の size={{ md: 3 }} と size="grow"
1つの要素の余白や色だけ Box+sx
中身の幅を最大幅で止めて中央に置く Container maxWidth="lg"

MUIのアイコンの使い方(@mui/icons-material)

この節では、Material Icons を部品として使う書き方と、import の書き方で何が変わるかが、ビルドの数値で分かります。

import Button from '@mui/material/Button'
import DeleteIcon from '@mui/icons-material/Delete'

<Button variant="contained" startIcon={<DeleteIcon />}>削除</Button>

アイコンは1つずつ @mui/icons-material/名前 のパスで import すると、ビルドが速く済みました。 手元の @mui/icons-material 9.5.0 には、アイコンのモジュールが10,750個(名前としては2,164種類に、Outlined・Rounded・Sharp・TwoTone の形の違い)あり、ファイルは43,009個でした。import { Delete } from '@mui/icons-material' の形(まとめて書き出す入口から取る形)だと、ビルドの時にこの全部が読まれます。

同じ画面(React+MUI だけの最小の画面)を、import の書き方を変えてビルドした結果です。

中身と import の形 読んだモジュール JS(gzip 後)
React だけ(MUI なし) 15 219.51kB(68.61kB)
Button(@mui/material/Button) 316 326.40kB(104.52kB)
Button({ Button } from '@mui/material') 901 326.29kB(104.28kB)
Button+アイコン(パスで1つ) 319 328.77kB(105.24kB)・0.27〜0.28秒
Button+アイコン({ Delete } from '@mui/icons-material') 11,653 328.67kB(104.98kB)・1.85〜2.15秒
DataGrid だけ 1,124 964.24kB(290.69kB)

できあがる JS の大きさは、どちらの import の形でもほぼ同じでした(使わない部品はビルドで取り除かれるため)。違ったのは読むモジュールの数とビルドの時間で、アイコンをまとめて import した形は11,653個を読み、ビルドが約7倍かかりました。開発サーバーの起動や、テストの実行でも同じように読む量が増えます。

フォントで表示する Icon 部品(<Icon>star</Icon>)を使う場合は、Google Fonts の Material Icons のフォントを別に読み込みます(公式のインストールのページ)。

MUI X(DataGridなど)の無料と有料の範囲

この節では、MUI X の部品のうち、どこまで無料で使えて、どこからライセンスが要るのかが分かります。料金は2026年10月23日時点の公式の料金ページの値です。

プラン 料金 入るパッケージ(主なもの)
Community 無料(MIT) x-data-grid・x-date-pickers・x-charts・x-tree-view・x-scheduler
Pro 年 299 ドル/開発者(月あたり 24.92 ドル) x-data-grid-pro・x-date-pickers-pro・x-charts-pro・x-tree-view-pro
Premium 年 599 ドル/開発者(月あたり 49.92 ドル) x-data-grid-premium・x-charts-premium・x-scheduler-premium
Enterprise 年 1,399 ドル/開発者(15席から) Premium+サポート

公式のライセンスのページは、DataGrid Pro の例として複数列での絞り込み・並べ替えや列の固定を、Premium の例として行のグループ化と Excel への書き出しを挙げています。ライセンスの数は「フロントエンドのコードを変更する、同時に作業する開発者の数」に合わせ、キーはプロジェクトに1回設定します。年ごとの契約(Annual)と、期限後も開発を続けられる買い切り(Perpetual)の2つの形があり、Pro・Premium には組織内の複数のアプリで使える Multi App License が付いています。

無料のDataGridの使い方と、1ページ100行の上限

npm install @mui/x-data-grid
import { DataGrid, type GridColDef } from '@mui/x-data-grid'

const columns: GridColDef[] = [
  { field: 'id', headerName: 'ID', width: 70 },
  { field: 'name', headerName: '名前', flex: 1 },
  { field: 'role', headerName: '役割', width: 120 },
  { field: 'score', headerName: '点数', type: 'number', width: 90 },
]

<Box sx={{ height: 400 }}>
  <DataGrid
    rows={rows}
    columns={columns}
    initialState={{ pagination: { paginationModel: { pageSize: 5 } } }}
    pageSizeOptions={[5, 10]}
    checkboxSelection
  />
</Box>

30行のデータで、点数の列の見出しを押して並べ替え、次のページへ進んだ結果です。

dg: rows=5 footer=1–5 of 30
sorted asc scores: 0,3,7,11,14
page2: 6–10 of 30

並べ替え・ページ送り・行の選択は無料版で動きました。無料版の DataGrid は1ページ100行までです。 pageSize に200を渡すと、画面が描かれず次のエラーになりました。

MUI X: `pageSize` cannot exceed 100 in the MIT version of the DataGrid.
You need to upgrade to DataGridPro or DataGridPremium component to unlock this feature.

ライセンスキーが無いとき(Pro・Premium)

開発用の環境で DataGridPro をキー無しで表示すると、表の上に「MUI X Missing license key」という透かしが出て、コンソールに次の文が出ました。

MUI X: Missing license key.

The license key is missing. You might not be allowed to use `@mui/x-data-grid-pro` which is part of MUI X Pro.

To solve the issue, you can check the free trial conditions: https://mui.com/r/x-license-trial.
If you are eligible no actions are required. If you are not eligible to the free trial, you need to purchase a license https://mui.com/r/x-get-license or stop using the software immediately.

公式のライセンスのページによると、本番以外の環境での評価なら30日間はライセンスなしで使え、キーは最初の部品が描かれる前に1回設定します。

import { LicenseInfo } from '@mui/x-license'

LicenseInfo.setLicenseKey('YOUR_LICENSE_KEY')

このとき、開発モードの Pro の部品はテレメトリー(利用状況の情報)を送る通信を始めました。公式のテレメトリーのページは、開発時だけ送り、本番のビルドでは取り除かれること、止めるには環境変数 MUI_X_TELEMETRY_DISABLED=true か muiXTelemetrySettings.disableTelemetry() を使うことを説明しています。

Date Pickers は日付のライブラリのアダプターと一緒に使います。公式は、ほかに日付のライブラリを使っていなければ Day.js をすすめています(npm install @mui/x-date-pickers dayjs)。

Next.jsでMUIを使う(App Router)

この節では、Next.js 16 の App Router で MUI を使う設定と、設定が足りないときに起きることが、ビルドとブラウザの実物で分かります。

設定の全体

npm install @mui/material @emotion/react @emotion/styled @mui/material-nextjs @emotion/cache

@mui/material-nextjs には v13-appRouter から v16-appRouter までの入口があり、Next.js の版に合わせて選びます。Next.js 16.4.2 では v16-appRouter を使いました。

// app/theme.js
'use client'
import { createTheme } from '@mui/material/styles'

const theme = createTheme({
  cssVariables: { colorSchemeSelector: 'class' },
  colorSchemes: { light: { palette: { primary: { main: '#0b5cad' } } }, dark: true },
})
export default theme
// app/layout.js
import { AppRouterCacheProvider } from '@mui/material-nextjs/v16-appRouter'
import InitColorSchemeScript from '@mui/material/InitColorSchemeScript'
import { ThemeProvider } from '@mui/material/styles'
import CssBaseline from '@mui/material/CssBaseline'
import theme from './theme'

export default function RootLayout({ children }) {
  return (
    <html lang="ja" suppressHydrationWarning>
      <body>
        <InitColorSchemeScript attribute="class" />
        <AppRouterCacheProvider>
          <ThemeProvider theme={theme}>
            <CssBaseline />
            {children}
          </ThemeProvider>
        </AppRouterCacheProvider>
      </body>
    </html>
  )
}
// app/page.js(サーバーコンポーネントのまま MUI の部品を置ける)
import Button from '@mui/material/Button'
import Typography from '@mui/material/Typography'
import Container from '@mui/material/Container'

export default function Home() {
  return (
    <Container sx={{ py: 4 }}>
      <Typography variant="h4" component="h1">Next.js と MUI</Typography>
      <Button variant="contained" sx={{ mt: 2 }}>保存</Button>
    </Container>
  )
}

next build は通り、/ は静的なページ(○ /)として作られました。

1つずつ外して起きたこと

外したもの 起きたこと(実測)
theme.js の 'use client' ビルドが止まる(Functions cannot be passed directly to Client Components)
AppRouterCacheProvider style タグが <head> でなく <body> に6つ。ブラウザで React のエラー #418
InitColorSchemeScript ダークの OS で、読み込み直後は白い背景、その後ダークに変わる
ページの onClick('use client' なし) ビルドが止まる(Event handlers cannot be passed to Client Component props.)

AppRouterCacheProvider のあり・なしで、サーバーが返した HTML を比べました。

あり: styles 3 in head 3 in body 0  クラス mui-1whm2rm
なし: styles 6 in head 0 in body 6  クラス css-1whm2rm

AppRouterCacheProvider は、サーバーで作った CSS を集めて <head> に入れる部品です。 無いときは style タグが部品のそばの <body> の中に散らばり、ブラウザでは「Minified React error #418」(サーバーの HTML とブラウザでの描画が合わない、ハイドレーションのエラー)が出ました。

ダークを選んだ OS(Chromium の colorScheme: 'dark')で、HTML を読み終えた瞬間(DOMContentLoaded)と描画が終わった後の状態です。

InitColorSchemeScript なし: at DOMContentLoaded:  | bg=rgb(255, 255, 255)
                            after hydration: dark | bg=rgb(18, 18, 18)
InitColorSchemeScript あり: at DOMContentLoaded: dark | bg=rgb(18, 18, 18)
                            after hydration: dark | bg=rgb(18, 18, 18)

スクリプトがあると、React が動く前に <html> に dark クラスが付き、白い画面が一瞬出る現象(ちらつき)が消えました。このスクリプトが <html> の属性を変えるので、公式の手順どおり <html> に suppressHydrationWarning を付けます。公式は、コードの中で theme.palette.mode === 'dark' で分岐すると同じちらつきの原因になるので、theme.applyStyles('dark', {…}) に置き換えるよう書いています。

ボタンを押したときの処理(onClick)を書くページやコンポーネントは、先頭に 'use client' を付けたクライアントコンポーネントにします。Tailwind CSS や CSS Modules と一緒に使う場合は <AppRouterCacheProvider options={{ enableCssLayer: true }}> にすると、MUI のスタイルが @layer mui に入り、ほかの CSS で上書きしやすくなります(公式の Next.js のページ)。App Router の基本は、関連記事「Next.js App Router 入門|v16対応・実際のビルド結果つき」で扱っています。

v7からv9への移行(Grid・system props・codemod)

この節では、v7 以前の解説のコードが v9 で動かない理由と、自動で書き換える方法が、実際の書き換えの差分で分かります。

v9 では、<Grid item xs={12}> の書き方(GridLegacy)と、<Box mt={2}> のような system props が外されました。 公式の移行ガイドの一覧から、よく当たるものを並べます。

v7 以前の書き方 v9 の書き方
<Grid item xs={12} md={6}> <Grid size={{ xs: 12, md: 6 }}>
<Box mt={2} p={1}> <Box sx={{ mt: 2, p: 1 }}>
<Grid container direction="column"> <Stack>
inputProps・InputProps slotProps.htmlInput・slotProps.input
components・componentsProps slots・slotProps
TransitionProps slotProps.transition
InfoOutline(アイコン) InfoOutlined
disableEscapeKeyDown(Dialog) onClose の reason を見る
<MenuItem> を Menu の外に置く Menu か MenuList の中に置く

v9 では、既定のビルドが対象にするブラウザも Chrome 117・Edge 121・Firefox 121・Safari 17.0 以上に上がりました(移行ガイド)。

v7の書き方のままv9で動かすとどうなるか

型チェックを通さずに(vite build だけで)ビルドすると、エラーは出ずに画面が崩れました。開発サーバーで測った結果です。

gridItem: class="MuiGrid-root MuiGrid-direction-xs-row css-17fpwt7-MuiGrid-root" xs="12" md="6" width=10
box: class="MuiBox-root css-0" mt="2" p="1" marginTop=0px padding=0px

xs="12"・mt="2" がそのまま HTML の属性になり、Grid の項目の幅は10px、Box の余白は0でした。コンソールには React の次のエラーが出ました。

Received `true` for a non-boolean attribute `item`.

If you want to write it to the DOM, pass a string instead: item="true" or item={value.toString()}.

v7 以前の解説や生成 AI のコードを貼ったとき、型エラーが出ないまま見た目だけが崩れることがあります。 TypeScript なら tsc で見つかります(エラーの節)。

codemodで書き換える

公式は書き換え用のツール(codemod)を出しています。v7 の Grid の書き方と v9 の system props を、それぞれ実行しました。TextField の inputProps などは deprecations/text-field-props で書き換えられます(移行ガイド)。

npx @mui/codemod@9.4.0 v9.0.0/system-props src
npx @mui/codemod@9.4.0 v7.0.0/grid-props src
-    <Stack spacing={2} mt={2}>
-      <Box mt={2} p={1}>A</Box>
-      <Typography mb={2}>B</Typography>
+    <Stack spacing={2} sx={{
+      mt: 2
+    }}>
+      <Box
+        sx={{
+          mt: 2,
+          p: 1
+        }}>A</Box>
+      <Typography sx={{
+        mb: 2
+      }}>B</Typography>
-      <Grid item xs={12} md={6}>A</Grid>
+      <Grid
+        size={{
+          xs: 12,
+          md: 6
+        }}>A</Grid>

2026年10月23日時点の最新の @mui/codemod 9.5.0 は、Node.js 22.22.2 で起動の時点で止まりました。

TypeError: yargs.command is not a function
    at Object.<anonymous> (…/node_modules/@mui/codemod/codemod.js:125:7)

9.5.0 は依存の yargs が ^18.1.0 に上がっていて、9.4.0 までは ^17 です。上のように @9.4.0 と版を指定すると動きました。アイコンの名前の変更(InfoOutline → InfoOutlined)のように codemod が無いものは、手で直します。

  • 1先に変更をコミットしたかcodemod はファイルを書き換える。--dry で試し、差分で確かめる
  • 2@mui のパッケージの版をそろえたかmaterial・icons-material・system・material-nextjs を 9 に。MUI X も 9 に
  • 3tsc でエラーが0かGrid の item・system props は型のエラーで見つかる
  • 4開発サーバーのコンソールにエラーが無いかMenu の外の MenuItem、Tabs の外の Tab は v9 で例外になる
  • 5テストの結果が変わっていないかv9 は Tabs・Menu・Stepper のキーボード操作と ARIA が変わった

MUIとshadcn/ui・Chakra UIの違い

この節では、React でよく比べられる UI の部品集との違いを、各公式の情報と npm の表示で比べられます。

比べる点 MUI(Material UI) shadcn/ui Chakra UI
入れ方 npm install @mui/material ほか CLI で部品のソースを書き込む npm i @chakra-ui/react @emotion/react
部品のコードの場所 node_modules 自分のプロジェクト node_modules
見た目の付け方 Emotion(既定) Tailwind CSS のクラス+CSS 変数 Emotion
デザインの元 Material Design 2 独自(プリセットで選ぶ) 独自
高機能な表・日付 MUI X(一部有料) 部品の組み合わせ ―
版(npm、2026年10月23日時点) 9.5.0 4.22.1(CLI) 3.37.0
ライセンス MIT MIT MIT

MUI は部品の更新を npm の版上げで受け取り、shadcn/ui は部品のソースを自分で持って直接直す、という考え方の違いがあります。v9 の NumberField のように、MUI でも Base UI の上にコピーして使う部品が出てきています。

状況 選びやすいもの
管理画面で、表・日付・フォームの部品を多く使う MUI(+MUI X)
Material Design の見た目と操作感をそのまま使いたい MUI
Tailwind CSS で作っていて、部品のコードも自分で持ちたい shadcn/ui
Emotion のスタイルで、Material Design ではない見た目で組みたい Chakra UI
既存の MUI のアプリに Tailwind CSS も使いたい MUI+enableCssLayer

shadcn/ui の仕組みと導入の手順は、関連記事「shadcn/uiとは|使い方・導入手順とエラーの直し方をViteで実演」で扱っています。Tailwind CSS v4 の導入は、関連記事「Tailwind CSS 使い方|v4の導入からつまずき対策まで実行結果つき」で扱っています。

MUIのよくあるエラーと直し方

この節では、エラー文から原因と直し方を引けます。すべて手元で実際に出た文です。

エラーの早見表

エラー文・症状 原因 直し方
Property 'item' does not exist on type …(TS2769) v7 以前の Grid の書き方 size={{ xs: 12 }} に。codemod v7.0.0/grid-props
Property 'mt' does not exist on type …(TS2769) v9 で system props が外れた sx={{ mt: 2 }} に。codemod v9.0.0/system-props
Cannot find module '@mui/material/Grid2' Grid2 は v7 で Grid に改名 @mui/material/Grid
Cannot find module '@mui/icons-material/InfoOutline' v9 で名前が変わった InfoOutlined
Type '"primary"' is not assignable to type … variant に無い名前 contained・outlined・text
Failed to resolve import "@emotion/react" Emotion を入れていない npm install @emotion/react @emotion/styled
MUI: MenuListContext is missing. MenuItem を Menu の外に置いた Menu か MenuList の中に
MUI X: `pageSize` cannot exceed 100 … 無料版の DataGrid の上限 100以下にするか Pro
Functions cannot be passed directly to Client Components テーマのファイルに 'use client' が無い 先頭に 'use client'
Event handlers cannot be passed to Client Component props. サーバーコンポーネントで onClick そのコンポーネントを 'use client' に
Minified React error #418(Next.js) AppRouterCacheProvider が無い layout を包む
TypeError: yargs.command is not a function @mui/codemod 9.5.0 と Node.js 22 @mui/codemod@9.4.0 を指定

Property 'item' does not exist(v7以前のGrid)

src/App.tsx(5,8): error TS2769: No overload matches this call.
  …
      Property 'item' does not exist on type 'IntrinsicAttributes & GridBaseProps & { sx?: SxProps<Theme> | undefined; } & Omit<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, keyof GridBaseProps | "sx">'.

型のエラーは長いですが、最後の行の Property '〇〇' does not exist を見ると、どの props が使えないかが分かります。system props(mt など)を Box・Stack・Typography に書いたときも、同じ形で Property 'mt' does not exist が出ました。

Grid2が見つからない

src/App.tsx(1,18): error TS2307: Cannot find module '@mui/material/Grid2' or its corresponding type declarations.

vite build では次の形でした。

"./Grid2" is not exported under the conditions ["module", "browser", "production", "import"] from package /…/node_modules/@mui/material (see exports field in /…/node_modules/@mui/material/package.json)

v6 の Grid2(新しい Grid)は v7 で Grid という名前になり、以前の Grid は GridLegacy になりました。v9 では GridLegacy も外されたので、@mui/material/Grid の1つだけです。

variantやcolorの名前の間違い

src/App.tsx(3,11): error TS2769: No overload matches this call.
  Overload 3 of 3, …, gave the following error.
    Type '"primary"' is not assignable to type 'OverridableStringUnion<"text" | "outlined" | "contained", ButtonPropsVariantOverrides> | undefined'.
  Overload 3 of 3, …, gave the following error.
    Type '"danger"' is not assignable to type 'OverridableStringUnion<"primary" | "inherit" | "secondary" | "success" | "error" | "info" | "warning", ButtonPropsColorOverrides> | undefined'.

<Button variant="primary" color="danger"> と書いたときです。ほかのライブラリの書き方(variant="primary")で書くとこうなります。型のエラーに、使える名前が全部出ます。

Failed to resolve import "@emotion/react"

@emotion/react が無い状態で開発サーバーを開くと、次のエラーで画面が出ませんでした。

[vite] (client) Pre-transform error: Failed to resolve import "@emotion/react" from "node_modules/.vite/deps/identifier-BMcS8ocg.js?v=dabaea58". Does the file exist?
  Plugin: vite:import-analysis

同じ状態の vite build は、"css" is not exported by "node_modules/@mui/styled-engine/index.mjs" などの23個のエラーで止まりました。エラー文に Emotion の名前が出ないことがあるので、@mui/styled-engine や css・keyframes が出たら、まず npm ls @emotion/react で入っているかを確かめます。

MenuListContext is missing(v9で例外になった)

MUI: MenuListContext is missing. MenuItems must be placed within Menu or MenuList.

<MenuItem> を Menu の外に単独で置いたときです。v9 から例外になり、画面全体が描かれなくなりました。一覧の行として使いたいときは ListItemButton を使います。

よくある質問

Q. MUIとは簡単に言うと何ですか? A. Google の Material Design の見た目の React の部品集「Material UI」と、それを作っている会社の名前です。ボタン・入力欄・ダイアログ・表などを import して使えます。

Q. MUIの読み方は? A. 「エム・ユー・アイ」です。公式ブログは、名前の意味を「Material to build UIs」、発音を /ɛm juː aɪ/ と書いています。

Q. MUIとMaterial UIの違いは? A. MUI は会社とブランドの名前で、Material UI はその中の部品集(@mui/material)です。2021年に「Material-UI」から今の名前に変わりました。

Q. MUIは無料ですか?商用利用できますか? A. Material UI 本体とアイコン、MUI X の Community(無料の DataGrid など)は MIT ライセンスで無料、商用でも使えます。MUI X の Pro は開発者1人あたり年 299 ドル、Premium は 599 ドルです(2026年10月23日時点)。

Q. MUIの最新バージョンは?v8はありますか? A. 2026年10月23日時点の npm の最新は 9.5.0 です。v8 は無く、MUI X と版の番号をそろえるために v7 の次が v9 になりました。

Q. MUIのGridでitemやxsが効きません。 A. v7 からは <Grid size={{ xs: 12, md: 6 }}> の書き方で、v9 では以前の書き方(GridLegacy)が外されました。v9 で item xs={12} と書くと、項目の幅が10pxになりました(移行の節)。

Q. sxとstyledはどちらを使えばよいですか? A. 1か所だけの調整なら sx、同じ見た目を何度も使う部品を作るなら styled です。どちらもテーマの値を使え、最後は同じ Emotion のクラスになります。

Q. MUIは重いですか? A. 手元の計測では、React だけの画面が gzip 後 68.61kB、Button を足すと 104.52kB、DataGrid を足すと 290.69kB でした。使った部品の分だけ増えます。アイコンはパスで1つずつ import すると、ビルドが速くなりました。

Q. Next.jsのApp Routerで使えますか? A. 使えます。@mui/material-nextjs の AppRouterCacheProvider で layout を包み、テーマのファイルに 'use client' を付けます。付けないとビルドが止まりました(Next.js の節)。

Q. Tailwind CSSと一緒に使えますか? A. 使えます。公式は、MUI のスタイルを @layer mui に入れる enableCssLayer(Vite では StyledEngineProvider、Next.js では AppRouterCacheProvider の options)と、@layer theme, base, mui, components, utilities; の順の宣言を案内しています。

Q. MUIとshadcn/uiはどちらを選べばよいですか? A. 表や日付などの部品を多く使う管理画面や、Material Design の見た目を使いたいなら MUI、Tailwind CSS で作っていて部品のソースを自分で持ちたいなら shadcn/ui が選ばれやすいです。比較は違いの節の表のとおりです。

Q. React Hook Formと組み合わせられますか? A. MUI の TextField は制御された入力の部品なので、React Hook Form の Controller で包んで使います。React Hook Form の書き方は、関連記事「React Hook Formの使い方|zod v4連携のコピペ例とエラー対処」で扱っています。

まとめ

  • MUI は会社とブランドの名前で、中心の製品は Material Design 2 の見た目の React の部品集 Material UI(@mui/material)。MIT で無料。読み方はエム・ユー・アイ。
  • 入れるのは @mui/material・@emotion/react・@emotion/styled。2026年10月23日時点の最新は 9.5.0 で、v8 は無い。
  • テーマは createTheme+ThemeProvider。colorSchemes: { dark: true } と useColorScheme でダークモード、jaJP で部品の文言が日本語になる。
  • sx は1か所の調整、styled は繰り返し使う部品。p: 2 は 16px。Stack の子の margin は useFlexGap を付けると効く。
  • v9 の Grid は size。item・xs・system props(mt など)は外れ、型チェックをしないと幅10pxなどの崩れになる。codemod は 9.4.0 を指定すると動いた。
  • アイコンはパスで1つずつ import。まとめて import すると、JS の大きさは同じでもビルドが約7倍かかった。
  • MUI X の DataGrid は無料版で並べ替え・ページ送りまで動き、1ページ100行まで。Pro は年 299 ドル/開発者から。
  • Next.js は AppRouterCacheProvider・テーマの 'use client'・InitColorSchemeScript の3つで、エラーとちらつきが消えた。

参考・出典

確認日はいずれも 2026年10月23日です。

  • MUI「Material UI - Overview」:https://mui.com/material-ui/getting-started/
  • MUI「Installation」:https://mui.com/material-ui/getting-started/installation/
  • MUI「All components」:https://mui.com/material-ui/all-components/
  • MUI「Theming」:https://mui.com/material-ui/customization/theming/
  • MUI「Dark mode」:https://mui.com/material-ui/customization/dark-mode/
  • MUI「CSS theme variables - Configuration」:https://mui.com/material-ui/customization/css-theme-variables/configuration/
  • MUI「Breakpoints」:https://mui.com/material-ui/customization/breakpoints/
  • MUI「Localization」:https://mui.com/material-ui/guides/localization/
  • MUI System「The sx prop」:https://mui.com/system/getting-started/the-sx-prop/
  • MUI「Grid」:https://mui.com/material-ui/react-grid/
  • MUI「Stack」:https://mui.com/material-ui/react-stack/
  • MUI「Number Field」:https://mui.com/material-ui/react-number-field/
  • MUI「Next.js integration」:https://mui.com/material-ui/integrations/nextjs/
  • MUI「Tailwind CSS v4 integration」:https://mui.com/material-ui/integrations/tailwindcss/tailwindcss-v4/
  • MUI「Upgrade to v9」(Material UI):https://mui.com/material-ui/migration/upgrade-to-v9/
  • MUI「Upgrade to v9」(MUI System):https://mui.com/system/migration/upgrade-to-v9/
  • MUI Blog「Introducing Material UI and MUI X v9」:https://mui.com/blog/introducing-mui-v9/
  • MUI Blog「Material UI v9.0」:https://mui.com/blog/introducing-material-ui-v9/
  • MUI Blog「2026 and beyond」:https://mui.com/blog/2026-and-beyond/
  • MUI Blog「Material-UI is now MUI」:https://mui.com/blog/material-ui-is-now-mui/
  • MUI「Pricing」:https://mui.com/pricing/
  • MUI X「Licensing」:https://mui.com/x/introduction/licensing/
  • MUI X「Telemetry」:https://mui.com/x/guides/telemetry/
  • MUI X「Data Grid - Pagination」:https://mui.com/x/react-data-grid/pagination/
  • MUI X「Date and Time Pickers - Getting started」:https://mui.com/x/react-date-pickers/getting-started/
  • npm「@mui/material」:https://www.npmjs.com/package/@mui/material
  • npm「@mui/codemod」:https://www.npmjs.com/package/@mui/codemod
  • shadcn/ui「Introduction」:https://ui.shadcn.com/docs
  • Chakra UI「Installation」:https://chakra-ui.com/docs/get-started/installation

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「MUI(Material UI)とは|使い方・テーマ・Gridをv9の実例で解説」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?