Material UI からの移行
アプリ管理のレイアウト、sx スタイル、テーマトークン、上書きを Master CSS に移し、Material UI のコンポーネント動作を保ちます。
このページの内容
Material UI と Master CSS は併用できます。多くのプロジェクトでは、アプリ管理のレイアウト、製品のサーフェス、繰り返す sx スタイルから移します。アクセシビリティ、状態管理、スロット、JavaScript の動作が役立つ Material UI コンポーネントは残します。
コンポーネントを一対一で書き直す作業と考えないでください。適切な移行では、明確な代替を用意するまで Button、Dialog、Menu、Select、DataGrid、テーマによるコンポーネントの上書きを残すこともよくあります。
#移行方針
アプリ管理のサーフェスごとに共通の移行手順を使います。Material UI が必要とする間は、ThemeProvider、CssBaseline、Emotion キャッシュ、SSR 設定を維持します。
sx を変換する前に境界を選びます。
| スタイルの管理対象 | 移行または維持 |
|---|---|
| アプリのレイアウトラッパー | 実際のテーマ尺度を解決してから静的な sx 値を変換します。 |
| 繰り返す製品のサーフェス | 共通トークンと、役立つならネイティブのコンポーネントクラスを定義します。 |
| MUI のスロットや owner-state の派生形 | slotProps、classes、styleOverrides、既存ラッパーをコンポーネントと共に残します。 |
| ダイアログ、メニュー、セレクト、データグリッド | 動作を維持し、置き換えを考える前にフォーカス、キーボード、状態をテストします。 |
併用で目的を達成するプロジェクトも多くあります。Master CSS がアプリのレイアウトや独自サーフェスを管理し、Material UI がインタラクティブなウィジェットを管理し続けます。
トークンを選ぶ前にテーマを解決する
既定の 8px 間隔、明示的な 8px の基準角丸、ルート文字サイズ 16px を使います。sx の同じ数値が同じ CSS 長さを表すとは限りません。
テキストによる説明
- 余白を解決する. 既定の余白関数で gap: 2 は 16px、p: 3 は 24px です。
- 形状を解決する. theme.shape.borderRadius を 8px にしたため、borderRadius: 2 は 16px になります。
- 一致するトークンを選ぶ. ルート 16px で gap-md と p-lg が一致し、独自の --radius-panel: 1rem が r-panel を供給します。
#Material UI と並べて Master CSS を追加する
アプリのスタイルシートから Master CSS をインポートし、現在の Material UI プロバイダーを残します。
@import "@master/css";多くの場合は既定のソース探索で十分です。独自の対象追加、除外、safelist、blocklist が必要な場合だけ明示的なソースディレクティブを追加します。
大規模な移行前にレンダリングモードを確認します。既定の静的レンダリングから始め、完全なクラス文字列を書き、既知のクラスを状態で切り替え、変わる値を CSS 変数で渡します。ブラウザーで新しいクラス名を作るアプリだけ、ランタイムやプログレッシブを選びます。
#テーマの値を @theme に移す
Material UI コンポーネントの外でも共有すべき、製品が管理する値から始めます。
import { createTheme } from '@mui/material/styles'export const theme = createTheme({ palette: { primary: { main: '#2563eb' }, background: { paper: '#ffffff' }, text: { primary: '#172033' } }, shape: { borderRadius: 8 }})@import "@master/css";@theme { --color-primary: #2563eb; --color-surface: #ffffff; --color-body: #172033; --radius-control: .5rem; --radius-panel: 1rem;}<section class="b(1) b-solid b-line-divider fg-body bg-surface r-control"> ...</section>Material UI の余白、ブレークポイント、角丸、パレットの尺度が Master CSS のプリセットと一致するとは考えないでください。製品のトークンを意図的に移し、既定トークンへの置換を確認します。
#アプリ管理の sx を変換する
レイアウトラッパー、カード、セクション、単純な製品 UI の sx から始めます。
import Box from '@mui/material/Box'export function DashboardPanel({ children }: { children: React.ReactNode }) { return ( <Box component="section" sx={{ display: 'grid', gap: 2, p: 3, borderRadius: 2, bgcolor: 'background.paper', color: 'text.primary' }}> {children} </Box> )}export function DashboardPanel({ children }: { children: React.ReactNode }) { return ( <section className="grid gap-md p-lg bg-surface fg-body r-panel"> {children} </section> )}既定の余白関数では、gap: 2 は 16px、p: 3 は 24px です。変換後のプリセット値はルートの文字サイズが 16px なら一致します。上のテーマでは、MUI の borderRadius: 2 は基準の 8px を二倍にして 16px にします。r-panel はパネルの役割を 1rem で表すので、アプリのルート文字サイズで比較してください。独自の余白関数には個別の対応付けが必要です。尺度の比較を妨げないよう、同じ section 要素と明示的なサーフェス/文字色の組を維持しています。
動作のために Material UI コンポーネントを残し、アプリ管理のラッパーからスタイルを変えます。
<div className="flex justify-flex-end"> <Button variant="contained">Save</Button></div>通常の非レイヤー Material UI/Emotion ルールは、インポート順に関係なくレイヤー内の Master CSS ユーティリティより優先されます。className の転送だけでは上書きを保証できません。カスケードレイヤーを意図的に設定して検証するまで、内部には sx、slotProps、classes を残します。
#繰り返すパターンをコンポーネントクラスに変換する
多くの sx が同じ製品上の役割を表すなら、Master CSS のコンポーネントクラスに移します。上の製品トークンも同じ CSS エントリーに残します。
@import "@master/css";@layer components { .panel { border-radius: var(--radius-panel); padding: var(--spacing-lg); border: 1px solid var(--color-line-divider); background-color: var(--color-surface); box-shadow: var(--shadow-sm); color: var(--color-body); } .toolbar { display: flex; align-items: center; gap: var(--spacing-sm); min-height: 3rem; }}<section className="panel"> <div className="toolbar"> ... </div></section>プロジェクトが管理する役割にはコンポーネントクラスを優先します。デザインシステムに残る Material UI コンポーネントには、Material UI のテーマの派生形を維持します。
#レスポンシブと状態のスタイルを扱う
静的でレスポンシブな sx を同じ境界の条件に変えます。既定の Material UI md は 900px、Master CSS のプリセットの md は 64rem からです。名前をコピーせず、元の境界を条件として定義します。
<Box sx={{ display: 'grid', gridTemplateColumns: { xs: '1fr', md: 'repeat(3, 1fr)' }, gap: 2 }} />@custom-media --mui-md (width >= 900px);<section class="grid (grid-template-columns:1fr) gap-md (grid-template-columns:repeat(3,1fr))@mui-md"> ...</section>状態が自分のマークアップのものなら、ネイティブな状態や属性を優先します。
<button type="button" class="bg-blue-60 fg-white bg-blue-70:hover (opacity:.5):disabled"> Save</button>selected、expanded、focused、error などがアプリ管理外の内部スロットや動作を対象にする場合は、MUI の上書きとして残します。
#移行を検証する
- 各作業後にフォーマッター、lint、型チェック、テスト、本番ビルドを実行します。
- 主要画面をライト/ダークテーマ、レスポンシブ境界、ホバー、focus-visible、無効、選択、読み込み状態で比較します。
- Material UI コンポーネントを削除する前に、ダイアログ、メニュー、セレクト、ポップオーバー、ポータル、トランジション、フォーカストラップをテストします。
- 残る Material UI や Emotion の経路で不要になるまで、Emotion キャッシュと SSR 設定を維持します。
- 視覚スタイルと動作の両方を置き換えてから、Material UI パッケージを削除します。

