はじめに
ReactのUIライブラリ、正直多すぎて選ぶの大変なんですよ。
Material UI、Ant Design、Chakra UI、shadcn/ui...どれも良さそうだけど、実際使ってみると「あれがない」「これが微妙」ってことが結構ある。
そんな中で、個人的にかなり気に入っているのがMantineです。
GitHubで30,200スター以上、月間ダウンロード数429万回以上。724人のコントリビューターによって活発に開発されています。2025年12月現在、バージョン8.3.10がリリースされたばかり。
「フル機能のReactコンポーネントライブラリ」を謳っているだけあって、本当に機能が充実している。これ、意外と重要なポイントなんですよね。
Mantineとは
Mantineは、120以上のカスタマイズ可能なコンポーネントと70以上のフックを提供する、機能豊富なReact UIライブラリです。
最大の特徴は「かゆいところに手が届く」設計。UIコンポーネントだけでなく、フォーム管理、通知システム、チャート、リッチテキストエディタまで、Webアプリ開発に必要なものが一通り揃っています。
30代になって思うのは、「あれもこれも別のライブラリを入れる」という運用の辛さ。Mantineなら、関連パッケージを公式が提供しているので、一貫性を保ちながら開発できます。
公式サイト: https://mantine.dev/ GitHub: https://github.com/mantinedev/mantine
特徴・メリット
1. ネイティブCSSによる高パフォーマンス
MantineはCSS-in-JSではなく、ネイティブCSSファイルでスタイルを提供しています。
// スタイルは.cssファイルとして出力される
import '@mantine/core/styles.css';
これ、意外と大きなメリットなんですよ。CSS-in-JSのランタイムオーバーヘッドがないので、パフォーマンスが良い。SSRとの相性も抜群です。
バンドルサイズも**2.79KB(minified + gzipped)**と軽量。コスパ的にかなりデカい。
2. 圧倒的なコンポーネント数
Mantineが提供するパッケージ構成:
- @mantine/core – 120以上のUIコンポーネント
- @mantine/hooks – 70以上のカスタムフック
- @mantine/form – 軽量なフォーム管理(6.3KB)
- @mantine/charts – rechartsベースのチャート
- @mantine/notifications – 通知システム
- @mantine/spotlight – コマンドパレット
- @mantine/code-highlight – コードハイライト
- @mantine/tiptap – リッチテキストエディタ
- @mantine/dropzone – ファイルアップロード
- @mantine/carousel – カルーセル
- @mantine/modals – モーダル管理
必要なものだけインストールすればいいので、無駄がない。この設計思想、好きですね。
3. ダークモード完全対応
全てのコンポーネントがダークモードに対応しています。設定も簡単。
import { MantineProvider } from '@mantine/core';
function App() {
return (
<MantineProvider defaultColorScheme="dark">
{/* 全コンポーネントがダークモードに */}
</MantineProvider>
);
}
ユーザーの設定に合わせて自動切り替えも可能です。時短になりますね。
4. Styles APIによる柔軟なカスタマイズ
コンポーネントの内部要素まで細かくスタイルを調整できます。
import { Button } from '@mantine/core';
function CustomButton() {
return (
<Button
styles={{
root: {
backgroundColor: '#228be6',
'&:hover': {
backgroundColor: '#1c7ed6',
},
},
label: {
fontWeight: 700,
},
}}
>
カスタムボタン
</Button>
);
}
内部構造を理解すれば、どんなデザインにも対応できる。これが他のライブラリとの差別化ポイントですね。
5. TypeScript完全対応
MantineはTypeScriptで書かれており、型推論がバッチリ効きます。
import { useForm } from '@mantine/form';
interface FormValues {
email: string;
name: string;
age: number;
}
function MyForm() {
const form = useForm<FormValues>({
initialValues: {
email: '',
name: '',
age: 0,
},
validate: {
email: (value) => (/^\S+@\S+$/.test(value) ? null : '無効なメールアドレス'),
name: (value) => (value.length < 2 ? '2文字以上で入力してください' : null),
},
});
return (
<form onSubmit={form.onSubmit((values) => console.log(values))}>
{/* フォームフィールド */}
</form>
);
}
型安全で開発体験が良い。IDEの補完も効くので、ドキュメントを見に行く頻度が減ります。
インストール方法
基本パッケージ
# npm
npm install @mantine/core @mantine/hooks
# yarn
yarn add @mantine/core @mantine/hooks
# pnpm
pnpm add @mantine/core @mantine/hooks
PostCSS設定(必須)
MantineはPostCSSプリセットを使用します。
npm install postcss postcss-preset-mantine postcss-simple-vars
postcss.config.jsを作成:
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',
},
},
},
};
アプリケーションのセットアップ
// app/layout.tsx (Next.js App Router)
import '@mantine/core/styles.css';
import { MantineProvider, ColorSchemeScript } from '@mantine/core';
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="ja">
<head>
<ColorSchemeScript />
</head>
<body>
<MantineProvider>{children}</MantineProvider>
</body>
</html>
);
}
基本的な使い方
ボタンコンポーネント
import { Button, Group } from '@mantine/core';
function ButtonExample() {
return (
<Group>
<Button>Default</Button>
<Button variant="outline">Outline</Button>
<Button variant="light">Light</Button>
<Button variant="subtle">Subtle</Button>
<Button variant="gradient" gradient={{ from: 'blue', to: 'cyan' }}>
Gradient
</Button>
</Group>
);
}
バリエーションが豊富。グラデーションボタンも一行で書けるのが嬉しい。
テキスト入力
import { TextInput, PasswordInput, Textarea } from '@mantine/core';
function InputExample() {
return (
<>
<TextInput
label="メールアドレス"
placeholder="your@email.com"
description="お知らせの送信に使用します"
required
/>
<PasswordInput
label="パスワード"
placeholder="パスワードを入力"
mt="md"
/>
<Textarea
label="メッセージ"
placeholder="お問い合わせ内容"
minRows={4}
mt="md"
/>
</>
);
}
label、description、errorが標準で用意されている。フォーム周りの実装がかなり楽になります。
カードコンポーネント
import { Card, Image, Text, Badge, Button, Group } from '@mantine/core';
function ProductCard() {
return (
<Card shadow="sm" padding="lg" radius="md" withBorder>
<Card.Section>
<Image
src="https://example.com/image.jpg"
height={160}
alt="Product"
/>
</Card.Section>
<Group justify="space-between" mt="md" mb="xs">
<Text fw={500}>製品名</Text>
<Badge color="pink">SALE</Badge>
</Group>
<Text size="sm" c="dimmed">
製品の説明文がここに入ります。
</Text>
<Button color="blue" fullWidth mt="md" radius="md">
購入する
</Button>
</Card>
);
}
useDisclosureフック
モーダルやドロワーの開閉管理に便利なフック。
import { useDisclosure } from '@mantine/hooks';
import { Modal, Button } from '@mantine/core';
function ModalExample() {
const [opened, { open, close }] = useDisclosure(false);
return (
<>
<Modal opened={opened} onClose={close} title="確認">
本当に削除しますか?
</Modal>
<Button onClick={open}>モーダルを開く</Button>
</>
);
}
これ、地味に便利なんですよ。状態管理のボイラープレートが減ります。
実践的なユースケース
1. フォームバリデーション
import { useForm } from '@mantine/form';
import { TextInput, NumberInput, Button, Box } from '@mantine/core';
function RegistrationForm() {
const form = useForm({
initialValues: {
name: '',
email: '',
age: 18,
},
validate: {
name: (value) => (value.length < 2 ? '名前は2文字以上で入力してください' : null),
email: (value) => (/^\S+@\S+$/.test(value) ? null : '有効なメールアドレスを入力してください'),
age: (value) => (value < 18 ? '18歳以上である必要があります' : null),
},
});
return (
<Box maw={400} mx="auto">
<form onSubmit={form.onSubmit((values) => console.log(values))}>
<TextInput
withAsterisk
label="名前"
placeholder="山田太郎"
{...form.getInputProps('name')}
/>
<TextInput
withAsterisk
label="メールアドレス"
placeholder="your@email.com"
mt="md"
{...form.getInputProps('email')}
/>
<NumberInput
withAsterisk
label="年齢"
placeholder="20"
mt="md"
min={0}
max={120}
{...form.getInputProps('age')}
/>
<Button type="submit" mt="xl" fullWidth>
登録
</Button>
</form>
</Box>
);
}
@mantine/formは依存関係がReactのみで6.3KB。軽量なのに機能は十分です。
2. 通知システム
import { notifications } from '@mantine/notifications';
import { Button, Group } from '@mantine/core';
function NotificationExample() {
const showSuccess = () => {
notifications.show({
title: '保存完了',
message: 'データが正常に保存されました',
color: 'green',
});
};
const showError = () => {
notifications.show({
title: 'エラー',
message: '処理中にエラーが発生しました',
color: 'red',
});
};
const showLoading = () => {
const id = notifications.show({
loading: true,
title: '処理中',
message: 'データを送信しています...',
autoClose: false,
withCloseButton: false,
});
setTimeout(() => {
notifications.update({
id,
color: 'teal',
title: '完了',
message: '送信が完了しました',
loading: false,
autoClose: 2000,
});
}, 3000);
};
return (
<Group>
<Button onClick={showSuccess} color="green">成功</Button>
<Button onClick={showError} color="red">エラー</Button>
<Button onClick={showLoading}>ローディング</Button>
</Group>
);
}
通知の更新もできるのがポイント。非同期処理のフィードバックに最適です。
3. レスポンシブグリッド
import { SimpleGrid, Card, Text } from '@mantine/core';
function ResponsiveGrid() {
const items = [1, 2, 3, 4, 5, 6];
return (
<SimpleGrid
cols={{ base: 1, sm: 2, lg: 3 }}
spacing={{ base: 'md', sm: 'lg' }}
>
{items.map((item) => (
<Card key={item} shadow="sm" padding="lg" radius="md" withBorder>
<Text>アイテム {item}</Text>
</Card>
))}
</SimpleGrid>
);
}
ブレークポイントごとの設定がオブジェクトで書ける。直感的で分かりやすい。
4. データテーブル
import { Table, Badge, ActionIcon, Group } from '@mantine/core';
import { IconEdit, IconTrash } from '@tabler/icons-react';
interface User {
id: number;
name: string;
email: string;
role: 'admin' | 'user';
}
const users: User[] = [
{ id: 1, name: '田中太郎', email: 'tanaka@example.com', role: 'admin' },
{ id: 2, name: '鈴木花子', email: 'suzuki@example.com', role: 'user' },
{ id: 3, name: '佐藤次郎', email: 'sato@example.com', role: 'user' },
];
function UserTable() {
const rows = users.map((user) => (
<Table.Tr key={user.id}>
<Table.Td>{user.id}</Table.Td>
<Table.Td>{user.name}</Table.Td>
<Table.Td>{user.email}</Table.Td>
<Table.Td>
<Badge color={user.role === 'admin' ? 'blue' : 'gray'}>
{user.role === 'admin' ? '管理者' : 'ユーザー'}
</Badge>
</Table.Td>
<Table.Td>
<Group gap="xs">
<ActionIcon variant="subtle" color="blue">
<IconEdit size={16} />
</ActionIcon>
<ActionIcon variant="subtle" color="red">
<IconTrash size={16} />
</ActionIcon>
</Group>
</Table.Td>
</Table.Tr>
));
return (
<Table striped highlightOnHover>
<Table.Thead>
<Table.Tr>
<Table.Th>ID</Table.Th>
<Table.Th>名前</Table.Th>
<Table.Th>メール</Table.Th>
<Table.Th>権限</Table.Th>
<Table.Th>操作</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
);
}
注意点
いいことばかり書いてきましたが、注意点もあります。
1. PostCSS設定が必須
ネイティブCSSを採用している分、PostCSSの設定が必要です。Create React AppやViteでは追加設定が必要になります。Next.jsなら比較的スムーズですが。
2. Tabler Iconsとの組み合わせ推奨
公式ドキュメントでは@tabler/icons-reactの使用が推奨されています。他のアイコンライブラリも使えますが、統一感を出すならTabler Iconsが無難です。
npm install @tabler/icons-react
3. バージョン7から8への移行
バージョン8でいくつかの破壊的変更があります。既存プロジェクトのアップグレード時は公式のマイグレーションガイドを確認してください。
4. 独自のデザインシステム
Material DesignやAnt Designのような既存のデザインシステムに基づいていないため、デザイナーとの連携時に調整が必要になることがあります。
まとめ
正直なところ、Mantineは「使い勝手の良さ」では頭一つ抜けていますね。
以下の条件に当てはまるなら、試してみる価値は間違いなくあります:
- Reactで機能豊富なUIを素早く構築したい
- ダークモード対応を簡単に実装したい
- フォーム管理や通知システムも統一したい
- TypeScriptで型安全に開発したい
- パフォーマンスを重視したい
30,200スター以上、92,500以上のプロジェクトで使用されているという実績が、その品質を証明しています。
個人的には、管理画面やダッシュボード、SaaSアプリケーションならMantine一択ですね。コンポーネントの豊富さとフックの便利さで、開発効率がかなり上がります。
まずは公式のテンプレートから始めてみてください。使いやすさに驚くはずです。QOL上がること間違いなしです。
公式サイト: https://mantine.dev/ GitHub: https://github.com/mantinedev/mantine ドキュメント: https://mantine.dev/docs/getting-started/