- 技術 💻
MUI(Material UI)とは|使い方・テーマ・Gridをv9の実例で解説
結論
MUIは、Material Designを実装したReactの部品集「Material UI」と、その開発元です。本体はMITライセンスで無料です。
この記事でわかること
- Vite+Reactに入れる5手順とビルドの実測値
- Next.jsで設定を外すと起きる問題4つの実測
- エラー原文12件(v7の書き方・Next.js等)
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 を強くすすめています。
入れた後にすること
Vite で React のプロジェクトを作る
npm create vite@latest app -- --template react-ts で作り、npm install。
MUI と Emotion を入れる
上の npm install の3つ。アイコンを使うなら @mui/icons-material も。
フォントを読み込む
MUI の既定の書体は Roboto。@fontsource/roboto を入れて、使う太さの CSS を import する。
テーマを作って渡す
createTheme で作り、ThemeProvider でアプリを包む。CssBaseline でブラウザごとの差をならす。
部品を import して置く
import Button from '@mui/material/Button' の形で1つずつ。
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個の行は省きました。)
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={{ p: 2, bgcolor: 'primary.main' }}。テーマの値を短い名前で使え、画面幅ごとの値も書ける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期連続の黒字決算。