Mantineとは?Viteでの導入手順とMantine 9の変更点を実装目線で解説【2026年8月版】
MantineはReact向けのUIコンポーネントライブラリで、公式リポジトリのREADMEでは @mantine/core が100種類以上のコンポーネント、@mantine/hooks が80種類以上のフックを提供すると説明されています。Viteと組み合わせた構成は公式ガイドが用意されている定番ですが、2026年3月31日公開のMantine 9でReact 19.2以上が必須になり、v7時代の手順はそのままでは動きません。この記事では、公式ガイドに沿った最小構成の導入手順、v9移行で壊れる箇所、CSSの読み込み方でバンドルサイズが7分の1に変わる実測値までを扱います。
まとめ
MantineをViteで使う際の要点は4つです。導入には @mantine/core と @mantine/hooks の2パッケージに加えてPostCSSプラグイン3点と postcss.config.cjs が要り、これを省くとMantine独自のmixinが動きません。次にバージョン要件。Mantine 9.5.1のpeerDependenciesはReact 19.2以上なので、React 18のプロジェクトは移行前にReactを上げる順序になります。3点目はCSSの読み込み方で、@mantine/core/styles.css を丸ごと読み込むと未使用コンポーネントのCSSまで出力に載り、最小構成でもCSSが230.90 kBに達しました。粒度別importなら32.71 kBまで落ちます。最後にプリプロセッサとの相性。LessやSassを併用すると、プリプロセッサがMantineのmixinをビルドエラーなしに黙って落とします。以下、それぞれの根拠と手順を説明します。
MantineというReact UIライブラリの位置づけ
100種類超のコンポーネントと80種類超のフックという構成
Mantineは単一パッケージではなく、用途別に分かれたパッケージ群です。「Mantine UI」と呼ばれることもありますが、実際に導入するパッケージ名は @mantine/core になります。このコアパッケージが100種類以上のコンポーネント、@mantine/hooks が80種類以上のフックを持ち、ほかにフォーム管理の @mantine/form、Recharts基盤の @mantine/charts、リッチテキストエディタの @mantine/tiptap、Mantine 9で追加された @mantine/schedule が並びます。ライセンスはMITです。
ボタンやフォーム部品だけが目的なら追加するのは @mantine/core と @mantine/hooks の2つで足り、チャートやエディタを使う段になってから対応パッケージを足せます。なお、検索結果に並ぶMantine React Tableは別プロジェクトのテーブルライブラリです。
パッケージ間のバージョン要件
npmレジストリ上の @mantine/core 最新版は9.5.1で、peerDependenciesは react ^19.2.0、react-dom ^19.2.0、@mantine/hooks 9.5.1 の3つで、Reactとreact-dom以外のUIフレームワークは含まれません。
注意したいのは @mantine/hooks の指定がキャレット付きではなく 9.5.1 という完全一致である点。@mantine/core だけを更新して @mantine/hooks を据え置くとpeerDependenciesの警告が出ます。Mantineのパッケージは常に同一バージョンへまとめて上げる運用が前提です。
公式が用意するフレームワーク別ガイドの現状
公式ドキュメントのリポジトリには、Next.js、Vite、React Router、Gatsby、RedwoodJSのフレームワーク別ガイドと、テスト向けのVitest・Jest、カタログ向けのStorybookのガイドが置かれています。ここで注意したいのが、Remix単独のガイドが存在しない点です。RemixはReact Router v7へ統合されたため、現在はReact Routerのガイドが対応します。「MantineはRemixに対応している」と書いた記事は、この統合前の情報とみてください。
Viteガイドがカバーする範囲は、プロジェクト作成、パッケージ導入、PostCSS設定、MantineProvider の配置までです。Vite側のビルド設定にMantine固有の追記は必要ありません。
ビルドツールとしてのViteの役割と読み方
Viteは公式ガイドの冒頭で「速い」を意味するフランス語だと説明され、発音は /viːt/、英語の「veet」のように読むと明記されています。日本語では「ヴィーテ」「ヴァイト」と書かれることがありますが、公式の発音記号に最も近いカタカナ表記は「ヴィート」です。役割は2つに分かれます。開発時はネイティブESMとCommonJSの違いを前提にモジュールをブラウザへそのまま配信し、変更した分だけを差し替えるHMRで画面へ反映、本番ビルド時はバンドラで最適化した静的アセットを出力します。
この「開発時はバンドルしない、本番だけバンドルする」という二段構えが、Viteの起動が速い理由です。本番ビルドを担うバンドラはVite 8で切り替わりました。2026年3月12日公開のVite 8.0からは、Rust製のRolldownが単一のバンドラとして採用されています。それ以前のバージョンで使われていたGo製バンドラのesbuildとRollupの二本立ては解消され、Vite 8.2.0の依存関係にesbuildは含まれません。
ViteプロジェクトへMantineを導入する手順
プロジェクト作成と2つのパッケージ導入
公式ガイドはVite本体のgetting startedでプロジェクトを作ってから、Mantineを足す順序を示しています。Reactテンプレートを指定して作成し、コアパッケージとフックパッケージを追加します。
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm install @mantine/core @mantine/hooks
npm install -D postcss postcss-preset-mantine postcss-simple-vars
最後の行のPostCSSプラグインは公式Viteガイドが前提にしている3点です。postcss-preset-mantine はpostcss-nested、Mantine独自のmixinを追加したpostcss-mixins、ピクセルをremへ変換する独自関数をまとめたプリセットで、これが無いとドキュメントのスタイル例が動きません。postcss-simple-vars の役割は限定的で、CSS内で $mantine-breakpoint-sm のような変数を書く場合にだけ必要になります。
postcss.config.cjs に書く2プラグイン
プロジェクト直下に postcss.config.cjs を作り、公式ガイドどおりの内容を置きます。ブレークポイントの数値はMantineの既定テーマと一致させてあります。
module.exports = {
plugins: {
'postcss-preset-mantine': {},
'postcss-simple-vars': {
variables: {
'mantine-breakpoint-xs': '36em',
'mantine-breakpoint-sm': '48em',
'mantine-breakpoint-md': '62em',
'mantine-breakpoint-lg': '75em',
'mantine-breakpoint-xl': '88em',
},
},
},
};
拡張子が .cjs である点は意図的です。Viteのテンプレートが生成する package.json には "type": "module" が入るため、postcss.config.js という名前で module.exports を書くと読み込みに失敗します。
styles.css の読み込みと MantineProvider の配置
アプリケーションのルートコンポーネントで、CSSの読み込みと MantineProvider の配置を行います。公式ガイドが示す最小形が次のコードです。
import '@mantine/core/styles.css';
import { MantineProvider } from '@mantine/core';
export default function App() {
return <MantineProvider>{/* Your app here */}</MantineProvider>;
}
MantineProvider はテーマとカラースキームをコンテキストで配下へ渡す役割を持ちます。これを置かないとコンポーネントはCSS変数を解決できません。CSSのimportは @mantine/hooks を除く全パッケージで必要で、たとえば通知を使うなら @mantine/notifications/styles.css を追加します。ここまで書いたら npm run dev で開発サーバーが起動し、npm run build で dist ディレクトリへ本番用の成果物が出力されます。
公式テンプレート vite-template を使う場合
手順を省くなら、Mantine公式のvite-templateリポジトリという選択肢もあります。GitHubスター230、最終pushは2026年8月2日で更新が続いており、PostCSS設定とプロバイダ配置が済んだ状態から始められるのが利点です。ただしテスト設定やLint設定も同梱するため、既存プロジェクトへ後から足すなら上の手順を自前でなぞるほうが差分を把握しやすくなります。
Mantine 9移行で壊れる箇所と対処
React 19.2という前提条件
Mantine 9.0.0は2026年3月31日に公開されました。移行で最初に確認すべきはReactのバージョンです。公式の8.x→9.x移行ガイドは、すべての @mantine/* パッケージがReact 19.2以降を必要とすると明記しています。同時に、React 19.2へまだ上げられない場合はMantine 8.xを使い続けてよいとも書かれています。
Text と Anchor の color 廃止と Typography への改称
v9では見た目に直結する2つの改名があります。Text と Anchor の color プロパティが削除され、スタイルプロパティの c に統一されました。TypographyStylesProvider は Typography へ改称されています。
// Mantine 8 までの書き方
<Text color="dimmed">本文</Text>
<TypographyStylesProvider><div dangerouslySetInnerHTML={{ __html: html }} /></TypographyStylesProvider>
// Mantine 9 での書き方
<Text c="dimmed">本文</Text>
<Typography><div dangerouslySetInnerHTML={{ __html: html }} /></Typography>
color は非推奨警告ではなく削除なので、残したままだと型エラーになるか、指定が無視されて既定色で描画されます。もうひとつ画面全体に効く変更が角丸の既定値。theme.defaultRadius は8.xの sm(4px)から9.xでは md(8px)へ変わったため、従来の見た目を保つなら createTheme で defaultRadius: 'sm' を明示します。このほかPopoverとTooltipの positionDependencies、use-fullscreenとuse-mouseの各フック、Gridの gutter から gap への改称にも変更が入っています。
useForm の第2ジェネリクスとバリデーションの変更
@mantine/form を使っている場合、useForm の第2ジェネリクスが変換関数の型から変換後の値の型へ変わりました。移行ガイドが示す新しい書き方は次のとおりです。
import { useForm } from '@mantine/form';
interface FormValues {
name: string;
locationId: string;
}
interface TransformedValues {
name: string;
locationId: number;
}
const form = useForm<FormValues, TransformedValues>({
mode: 'uncontrolled',
initialValues: { name: '', locationId: '2' },
transformValues: (values) => ({ ...values, locationId: Number(values.locationId) }),
});
スキーマバリデーションの入口も変わりました。zodResolver は @mantine/form からエクスポートされなくなり、汎用の schemaResolver に統合されています。Zodを使っていたコードは validate: schemaResolver(schema, { sync: true }) の形へ書き換えが必要です。
tiptap と recharts の同時更新
周辺パッケージにも連鎖します。@mantine/tiptap を使っているならTiptapを3系へ、@mantine/charts を使っているならRechartsを3系へ上げる必要があります。Rechartsは移行作業不要と公式が明記していますが、TiptapはMantineとは別に専用の移行ガイドが用意されており、相応の作業量を見込んでください。リッチテキストエディタを含むプロジェクトでは、Mantine 9移行のコストの大半がTiptap側になります。
CSSの読み込み方で変わるバンドルサイズ
styles.css 一括読み込みの出力サイズ
公式ガイドが示す @mantine/core/styles.css の一括読み込みは、全コンポーネントのCSSをまとめた1ファイルを読む書き方です。実体は273,027バイトあります。ButtonとGroupしか使わない最小構成でも、この全量が出力に載ります。Node 26.5.0・Vite 8.2.0・Mantine 9.5.1・React 19.2.8で、ButtonとGroupだけを描画するプロジェクトをビルドした結果が次の表です。
| 読み込み方 | CSS出力 | CSS(gzip) | 一括比 |
|---|---|---|---|
| styles.css 一括 | 230.90 kB | 33.76 kB | 100% |
| 粒度別 3本 | 32.71 kB | 5.66 kB | 14% |
| 粒度別 10本 | 61.99 kB | 10.03 kB | 27% |
| 粒度別 20本 | 88.74 kB | 14.09 kB | 38% |
粒度別の行は、グローバル3ファイルに加えて読み込んだコンポーネントCSSの本数です。3本はUnstyledButton・Button・Group、10本はそこにPaper・Input・Table・Badge・Card・Tabs・Alertを、20本はさらにAccordion・ActionIcon・Avatar・Checkbox・Chip・Menu・Modal・Popover・Progress・Tooltipを足した構成で、どのコンポーネントを選ぶかで実測値は上下します。JS側の出力はどの構成でも243.96 kBで変わりません。CSSの読み込み方はJSのツリーシェイキングとは独立しているため、使うコンポーネントを絞ってもimportを書き換えなければCSSは減らないということです。
粒度別importへの切り替え手順
コンポーネント単位のCSSはMantine 7.3.0(2023年12月4日公開)から個別ファイルとして同梱され、8.0.0でグローバルCSSが3ファイルへ分割されました。粒度別に読み込む場合は、グローバル3点に加えて使うコンポーネントのCSSを列挙します。
import '@mantine/core/styles/baseline.css';
import '@mantine/core/styles/default-css-variables.css';
import '@mantine/core/styles/global.css';
import '@mantine/core/styles/UnstyledButton.css';
import '@mantine/core/styles/Button.css';
import '@mantine/core/styles/Group.css';
3つのグローバルファイルは役割が分かれています。baseline.css は最小限のリセットで box-sizing とフォント関連を設定し、default-css-variables.css は既定テーマから生成したCSS変数を、global.css はコンポーネントが使う共通クラスを持ちます。この3つはどれも省けません。
上の例で UnstyledButton.css を入れている理由は、コンポーネント間に依存があるためです。公式のCSS files listは、ButtonがUnstyledButtonを土台にしているのでButtonを使うならUnstyledButtonのスタイルもimportが必要だと明記しています。Selectのように自前のスタイルを持たず他コンポーネントの上に成り立つものもあるため、依存が読めないときは同ページが挙げる再利用される側のCSS一式をまとめて入れる方法が案内されています。
粒度別importを選ばないほうがよい場面
削減幅はコンポーネント数とともに縮みますが、20本まで増やしても一括読み込みの38%にとどまりました。サイズだけを見れば粒度別importが不利になる地点は当面ありません。判断を分けるのは運用コストのほうです。
コンポーネントを追加するたびにimport行の追加が必要で、追加を忘れるとスタイルが当たらない状態で描画されます。ビルドは通り型エラーも出ないため、レビューで気づきにくい種類の不具合です。依存関係の見落としも同じ形で表面化します。したがって、使うコンポーネントが固定されているランディングページや小規模な社内ツールでは粒度別import、画面数と担当者が増えていく管理画面では styles.css 一括のほうが事故が少なくなります。
LessやSassをMantineプロジェクトで使うときの落とし穴
LessとViteは比較対象ではないという整理
「Less と Vite のどちらを使うか」という形で検索されることがありますが、この2つは選択の対象になりません。LessはCSSに変数やネストを持ち込むCSSプリプロセッサ、Viteは開発サーバーと本番ビルドを担うビルドツールです。層が違うため、Viteのプロジェクトの中でLessを使うのが正しい組み合わせになります。比べる相手を探すなら、Lessの対抗はSassやStylus、Viteの対抗はwebpackやNext.js 16で既定になったTurbopackです。
Viteが内蔵対応する5拡張子と別途必要なコンパイラ
Viteは .scss、.sass、.less、.styl、.stylus の各拡張子を内蔵で扱います。専用のViteプラグインは不要ですが、コンパイラ本体は自分で入れる必要があります。
npm install -D sass-embedded # または sass
npm install -D less
npm install -D stylus
インストールすれば import './style.module.less' のように書くだけで通り、設定ファイルへの追記も要りません。
.less 併用時に消えるmixinと残る rem 関数
問題はMantineと併用したときに起きます。postcss-preset-mantine が提供する @mixin dark、@mixin light、@mixin larger-than といったMantine独自のmixinは、あくまでPostCSSのプラグインとして動くものです。一方Viteの処理順ではプリプロセッサが先に走るため、Lessが @mixin という記述を先に解釈してしまいます。
同じ内容をCSS ModulesとLessで書いた場合の出力を比べると差が明確に出ます。まずCSS Modulesの側です。
/* Demo.module.css */
.root {
padding: rem(16px);
@mixin dark {
background: #000;
}
}
これをビルドすると、._root_xxxxx_1{padding:calc(1rem * var(--mantine-scale))} と [data-mantine-color-scheme=dark] ._root_xxxxx_1{background:#000} の2つが出力されます。クラス名のハッシュ部分は環境によって変わりますが、ダークモード用のセレクタが生成される点は共通です。
ところが拡張子を .less に変えて同じ内容を書くと、出力に残るのは padding の行だけで、ダークモード用のルールは消えます。しかもビルドは成功し、警告もエラーも出ません。ピクセルをremへ変換する rem() 関数のほうはLessが素通しするためPostCSS側で処理され、両方で正しく機能します。つまり一部だけ動くので、動作していると誤認しやすい状況になります。
結論として、MantineのコンポーネントスタイルはCSS Modulesで書いてください。既存資産の都合でLessやSassを使う必要があるなら、Mantineのmixinを使う箇所だけ .module.css に分離し、プリプロセッサのファイルにはMantine固有の記述を持ち込まない切り分けが安全です。
Mantineプロジェクトで触るVite設定
起動ポートの固定とホストの公開
Viteの開発サーバーは既定でポート5173、ホスト localhost で起動します。ポートが埋まっていると自動で次の空きポートへずれるため、フロントのURLを前提にした設定がある環境では固定したほうが安全です。strictPort を有効にすると、指定ポートが使用中の場合はずらさずに起動を失敗させます。
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
server: {
port: 5173,
strictPort: true,
host: true,
open: true,
hmr: { overlay: false },
proxy: {
'/api': {
target: 'http://localhost:8000',
changeOrigin: true,
},
},
},
build: {
outDir: 'dist',
sourcemap: true,
},
});
host: true は同一ネットワークの他端末へサーバーを公開する指定で、実機のスマートフォンで表示を確認したいときに使います。open: true は起動時にブラウザを自動で開く指定。文字列を渡せば特定のパスを開けます。hmr.overlay はエラー時に画面を覆うオーバーレイの制御で、既定の有効状態が邪魔になる場面では false にします。
バックエンドAPIへの中継設定
上の proxy は、開発サーバーが受けた /api 宛のリクエストを別ポートのバックエンドへ転送する設定です。フロントとAPIをオリジンが異なる状態で並走させるとCORSの対応が必要になりますが、プロキシを挟めば開発中は同一オリジンとして扱えます。changeOrigin は転送時にHostヘッダを転送先へ書き換える指定で、Hostを見て振り分けるサーバーが相手のときに必要です。
Vite 8のRolldown化とNode要件
Vite 8.2.0のengines指定は node ^20.19.0 || >=22.12.0 です。Node 18系はすでに対象外なので、CIのNodeバージョンを固定している場合は先に確認してください。build.target の既定値は baseline-widely-available で、リリースから2年半以上経過したブラウザ群が対象になります。開発時のトランスパイル対象は esnext、出力先の既定は dist、ソースマップは既定で無効です。古いブラウザ向けには @vitejs/plugin-legacy を別途使います。
Rolldownへの切り替えはプラグイン互換性を保った形で行われているため、多くのプロジェクトでは設定変更なしに上がります。テスト環境を揃えるなら、同じ変換パイプラインを共有するViteネイティブなテスト基盤のVitestを使うと、ビルドとテストで挙動がずれにくくなります。
Mantineを選ばない方がよい場面
MantineはReactの管理画面や社内ツールでは有力ですが、次の条件に当てはまるなら別の選択肢を検討してください。
- VueやAngular、SvelteへUI層を移す可能性がある場合。
@mantine/coreのpeerDependenciesはReactに固定されており、これらへ移すならUI層は書き直しになります。 - React 19.2へ上げられない事情がある場合。Mantine 9は使えず8.x系に留まるため、v9で追加されたコンポーネントは選択肢から外れます。
- デザインシステムが既に確立していて、既存のトークンやコンポーネント仕様に合わせ込む必要がある場合。Mantineはテーマ機能が充実している反面、CSS変数とmixinという独自の作法に乗る前提なので、外部の設計へ寄せるほど利点が薄れます。
- CSSの出力サイズが厳しく制約される公開ページ。粒度別importでも32.71 kB、gzipで5.66 kBのCSSが最低限必要になります。
逆に、画面数が多く入力フォームが中心で、デザインの独自性より実装速度が優先される用途では、100種類超のコンポーネントとフォーム管理パッケージが揃っている利点がそのまま効きます。
よくある質問
Mantineの読み方は何ですか?
公式ドキュメントとGitHubリポジトリのREADMEには、2026年8月時点で発音の記載がありません。リポジトリ全体を「pronounced」で検索しても該当は0件です。Viteが公式ガイドの冒頭で発音記号を明示しているのとは対照的で、Mantine側には拠り所となる一次情報が無い状態といえます。日本語では「マンティン」「マンティーン」の両方が使われますが、いずれも公式見解ではないため、社内で表記を1つに決めておくのが実務的です。
MantineはVueやAngularで使えますか?
使えません。@mantine/core のpeerDependenciesは react と react-dom のみで、Vue向けやAngular向けの公式パッケージは提供されていません。Viteのプロジェクトであっても、テンプレートがVueならMantineは選べない点に注意してください。
React 19.2へ上げられない場合はどうすればよいですか?
Mantine 8.xを使い続けて問題ありません。公式の8.x→9.x移行ガイドが、React 19.2以上へ更新できるようになるまでMantine 8.xを継続してよいと明記しています。Reactの更新が先、Mantineの移行が後という順序になります。
LaravelのViteは別物ですか?
同じViteです。Laravelは laravel-vite-plugin というViteプラグインを通してViteを組み込む構成で、2026年8月時点の最新版は3.1.3、peerDependenciesは vite ^8.0.0 と fontaine ^0.8.0 の2件です。BladeテンプレートからViteのビルド成果物を読み込む役割を担うもので、Vite本体の設定の考え方はそのまま通用します。
Mantineでモバイル対応はどう書きますか?
ルート要素を持つ全コンポーネントが hiddenFrom と visibleFrom のプロパティに対応しており、ブレークポイント名を渡すだけで表示を切り替えられます。JavaScript側で分岐したい場合は use-media-query か use-matches のフック。CSS側で書くなら、postcss-preset-mantine の @mixin larger-than と @mixin smaller-than がブレークポイント変数を受け取れます。