1. テーブルコンポーネントの種類
Reactテーブル関連コンポーネントとして、主に3種類が存在します。
1. Table (@mantine/core)
- 概要: Mantineのコアライブラリに含まれる基本的なテーブルコンポーネント。シンプルなデータ表示に適し、テーマスタイル(例: ダークモード対応)が自動適用されます。
-
主な特徴:
- Sticky header(固定ヘッダー)、ストライプ行、ホバー効果、スクロールコンテナ。
- データpropで自動行生成可能。
- 行選択(チェックボックス)や垂直レイアウト対応。
- 使いどころ: 軽量で基本的なテーブルが必要な場合。高度な機能(ソート、フィルタリング)は手動実装。
-
インストール:
@mantine/core
をインストール(標準)。
2. DataTable (@mantine/datatable)
- 概要: Mantineの拡張パッケージで、データリッチなアプリケーション向けのテーブル。軽量で依存関係なし、Mantine V8対応。
-
主な特徴:
- ソート、ページネーション、行選択(Gmail風のバッチ選択)、ダークモードサポート。
- 非同期データロードやカスタムセルレンダリング。
- 違い: 基本Tableよりデータグリッドのような機能が追加され、UIが洗練。データ量が多い場合に便利だが、TanStackベースではないためシンプル。
- 使いどころ: 中規模のデータテーブルで、軽量さを重視する場合。
-
インストール:
npm install @mantine/datatable
。
3. Mantine React Table
- 概要: TanStack React TableをMantineスタイルでラップした独立ライブラリ(KevinVandy/mantine-react-table)。Mantine V7/V8対応(V2でV8サポート)。
-
主な特徴:
- 高度な機能: ソート、フィルタリング、ページネーション、行編集/作成、列リサイズ、行展開。
- ユーザーfriendlyなUIとデフォルト設定。
- 違い: 他の2つよりパワフルで、行編集などの先進機能あり。依存関係(TanStack Table)があるため、複雑なテーブルに最適。
- 使いどころ: 大規模アプリやカスタム機能が必要な場合。
-
インストール:
npm install mantine-react-table @mantine/core
。
例えば、シンプルならTable、データ操作ならDataTable、高度ならMantine React Tableを選択するのがいいです。2025年現在、Mantine 8.0リリース後もこれら3つが並存しています。
2. 基本の使い方
1. Table (@mantine/core)
シンプルなデータ表示に適し、テーマスタイルが自動適用されます。手動で行を作成するか、data propで自動生成できます。主な特徴は、sticky header、ストライプ行、ホバー効果、スクロール対応です。
-
手動行作成例: データ配列をmapして行を作成。
import { Table } from '@mantine/core'; const elements = [ { position: 6, mass: 12.011, symbol: 'C', name: 'Carbon' }, { position: 7, mass: 14.007, symbol: 'N', name: 'Nitrogen' }, // 他のデータ ]; function BasicTable() { const rows = elements.map((element) => ( <Table.Tr key={element.name}> <Table.Td>{element.position}</Table.Td> <Table.Td>{element.name}</Table.Td> <Table.Td>{element.symbol}</Table.Td> <Table.Td>{element.mass}</Table.Td> </Table.Tr> )); return ( <Table> <Table.Thead> <Table.Tr> <Table.Th>Position</Table.Th> <Table.Th>Name</Table.Th> <Table.Th>Symbol</Table.Th> <Table.Th>Mass</Table.Th> </Table.Tr> </Table.Thead> <Table.Tbody>{rows}</Table.Tbody> </Table> ); }
-
data prop使用例: オブジェクトで自動生成。
import { Table } from '@mantine/core'; const tableData = { caption: 'Elements', head: ['Position', 'Name', 'Symbol', 'Mass'], body: [ [6, 'Carbon', 'C', 12.011], [7, 'Nitrogen', 'N', 14.007], ], }; function AutoTable() { return <Table data={tableData} />; }
-
キーpropと説明:
-
stickyHeader
: true - ヘッダーを固定。 -
horizontalSpacing
: 'md' - セルパディング調整。 -
withTableBorder
: true - テーブルボーダー追加。 -
captionSide
: 'bottom' - キャプション位置。
-
2. DataTable (@mantine/datatable)
DataTableは拡張パッケージで、データリッチなテーブル向け。recordsとcolumnsを設定するだけで、ソートやページネーションが使えます。主な特徴は、軽量、非同期ロード対応、行選択、列スタイリング。
-
基本例: records(データ配列)とcolumns(列定義)を指定。
import { DataTable } from 'mantine-datatable'; const companies = [ { id: 1, name: 'Company A', city: 'Tokyo', employees: 100 }, { id: 2, name: 'Company B', city: 'Osaka', employees: 200 }, // 他のデータ ]; function BasicDataTable() { return ( <DataTable records={companies} columns={[ { accessor: 'name', title: 'Company Name' }, { accessor: 'city', title: 'City' }, { accessor: 'employees', title: 'Employees', sortable: true }, ]} withTableBorder /> ); }
-
ソート・ページネーション追加例: stateで管理。
import { DataTable } from 'mantine-datatable'; import { useState } from 'react'; function SortedDataTable({ records }) { const [sortStatus, setSortStatus] = useState({ columnAccessor: 'employees', direction: 'asc' }); return ( <DataTable records={records} columns={[ { accessor: 'name', title: 'Name' }, { accessor: 'employees', title: 'Employees', sortable: true }, ]} sortStatus={sortStatus} onSortStatusChange={setSortStatus} totalRecords={records.length} recordsPerPage={10} page={1} onPageChange={(p) => console.log(p)} /> ); }
-
キーpropと説明:
-
records
: データ配列(必須)。 -
columns
: 列オブジェクト配列(accessorでキー指定、titleでヘッダー、sortable: trueでソート有効)。 -
withColumnBorders
: true - 列ボーダー追加。 -
fetching
: true - ロード中インジケーター表示。
基本的にrecordsとcolumnsで即テーブル生成可能。
-
3. Mantine React Table
useMantineReactTableフックで設定し、ソート・フィルタリング・ページネーションがデフォルト有効。主な特徴は、列リサイズ、行選択、拡張性高く、大規模データ向け。
-
hook使用例: columnsとdataをuseMemoで定義。
import { useMemo } from 'react'; import { MantineReactTable, useMantineReactTable } from 'mantine-react-table'; const data = [ { firstName: 'John', lastName: 'Doe', city: 'Tokyo', age: 30 }, { firstName: 'Jane', lastName: 'Smith', city: 'Osaka', age: 25 }, // 他のデータ ]; function BasicMRT() { const columns = useMemo(() => [ { accessorKey: 'firstName', header: 'First Name' }, { accessorKey: 'lastName', header: 'Last Name' }, { accessorKey: 'city', header: 'City' }, { accessorKey: 'age', header: 'Age' }, ], []); const table = useMantineReactTable({ columns, data, enableSorting: true, enablePagination: true, }); return <MantineReactTable table={table} />; }
-
直接prop例: hookなしでシンプルに。
import { useMemo } from 'react'; import { MantineReactTable } from 'mantine-react-table'; // dataとcolumnsは上記と同じ function DirectMRT() { return <MantineReactTable columns={columns} data={data} />; }
-
キーpropと説明:
-
columns
: 配列(accessorKeyでデータキー、headerでヘッダー)。 -
data
: データ配列(安定したもの推奨)。 -
enableFiltering
: true - フィルタリング有効(デフォルト)。 -
enableRowSelection
: true - 行選択有効。
-
3.Mantineのテーブル機能比較表
機能・特徴 | @mantine/core Table | @mantine/datatable | mantine-react-table |
---|---|---|---|
ソート | 非対応(手動実装) | 対応 | 対応 |
ページネーション | 非対応 | 対応 | 対応 |
行選択(チェック) | 非対応 | 対応 | 対応(柔軟に設定可能) |
フィルタリング | 非対応 | 非対応(手動で追加可能) | 対応(標準機能) |
行の編集・作成 | 非対応 | 非対応 | 対応 |
列のリサイズ | 非対応 | 非対応 | 対応 |
必要な依存ライブラリ | なし | なし | TanStack Table に依存 |
適している規模 | 小規模 | 中規模 | 大規模・複雑な要件に対応可能 |
4.各コンポーネントの制限・注意点
1. @mantine/core
の Table
コンポーネント
主な制限・注意点
項目 | 説明 |
---|---|
data prop の柔軟性が低い |
data prop を使うと、ヘッダーとボディが固定構造になるため、カスタマイズ性が低い。複雑なセル(ボタン、リンク、条件分岐など)には不向き。 |
ソート・ページネーション非対応 | 自前でロジックを実装する必要がある。状態管理やUIの整備が必要。 |
行選択(チェックボックス)非対応 | 状態管理を含めて完全に手動実装が必要。複雑になりやすい。 |
レスポンシブ非対応 | テーブル幅の自動調整や折り返しには自力でCSS対応が必要。 |
拡張性が限られる | 本質的には静的なHTMLテーブルに近いため、インタラクティブな機能は追加しづらい。 |
使い方の注意点
- UIが単純で、表示するだけの用途なら十分。
- 複雑な操作をさせたい場合は他のテーブルに切り替えることを検討。
2. @mantine/datatable
コンポーネント
主な制限・注意点
項目 | 説明 |
---|---|
Mantine公式だが拡張的 | Mantineの本体ではなく別パッケージ。メンテナンスの速度やIssue対応が若干遅れる傾向がある(GitHub上のIssue解決までに日数を要することも)。 |
カスタマイズ限界あり | 独自の柔軟なカスタムUI(例:マルチセル内コンポーネント、動的な列追加など)はやや難しい。 |
フィルタリングは非対応 | 自前実装が必要。検索ボックスやセレクトなどのUIと状態管理を別で用意する必要がある。 |
拡張性は中程度 | データを整えて渡すことで簡単に使えるが、複雑な挙動(編集・列ドラッグなど)には非対応。 |
タイピングはあるが簡易 | TypeScript対応だが、型推論や列定義の柔軟性は限定的。大規模開発にはやや不足。 |
使い方の注意点
- 管理画面などで「そこそこ複雑だけど、限界まで拡張しない」用途に向いている。
- フィルタやリアルタイム更新が必要な場合は補助実装が必要。
3. mantine-react-table
(mantine-react-table
+ @tanstack/react-table
)
主な制限・注意点
項目 | 説明 |
---|---|
TanStack Table に依存 | 内部的に TanStack Table を使っており、そのバージョン(v8など)に強く依存するため、バージョンアップに伴う破壊的変更に注意が必要。 |
型定義が複雑 | TypeScript環境で使う場合、columns や data の型指定がやや煩雑。初心者には難しいこともある。 |
設定項目が非常に多い | 柔軟にカスタマイズできる反面、初期設定のコード量が多くなりがち。使いこなすにはドキュメント熟読が必要。 |
パフォーマンスチューニング必要 | 仮想スクロールやデータ量が多いときに、useMemo や仮想化などの知識が求められる。 |
学習コストが高め | 他の2つと比較して、概念やフック構成が複雑。習得に少し時間がかかる。 |
使い方の注意点
- 柔軟で機能豊富な反面、構築・保守コストが上がる。
- チーム内で共通の知識を持っておくことが大切。
5.TypeScriptで型安全に扱うための実例
1. @mantine/core
の Table
における型の使い方
基本的な考え方
-
Table
は汎用的なテーブルなので、型安全な配列操作(map
)で自前で制御します。 - 型定義を作って、
map
時の補完やミス防止に活用。
実装例
type Element = {
position: number;
name: string;
symbol: string;
mass: number;
};
const elements: Element[] = [
{ position: 1, name: 'Hydrogen', symbol: 'H', mass: 1.008 },
{ position: 6, name: 'Carbon', symbol: 'C', mass: 12.011 },
];
function TypedTable() {
const rows = elements.map((element) => (
<Table.Tr key={element.name}>
<Table.Td>{element.position}</Table.Td>
<Table.Td>{element.name}</Table.Td>
<Table.Td>{element.symbol}</Table.Td>
<Table.Td>{element.mass}</Table.Td>
</Table.Tr>
));
return (
<Table>
<Table.Thead>
<Table.Tr>
<Table.Th>Position</Table.Th>
<Table.Th>Name</Table.Th>
<Table.Th>Symbol</Table.Th>
<Table.Th>Mass</Table.Th>
</Table.Tr>
</Table.Thead>
<Table.Tbody>{rows}</Table.Tbody>
</Table>
);
}
補足
-
Element
型を明示することで、キーや値のミスを防げます。 -
key
にelement.name
など、型の一意性も担保できます。
2. @mantine/datatable
における型定義
ポイント
-
records
配列に型をつける。 -
columns
のaccessor
は文字列なので、型安全とは言えないが、as const + keyof を活用すればある程度安全性を確保できます。
型付き実装例
type Company = {
id: number;
name: string;
city: string;
employees: number;
};
const records: Company[] = [
{ id: 1, name: 'Company A', city: 'Tokyo', employees: 100 },
{ id: 2, name: 'Company B', city: 'Osaka', employees: 200 },
];
function CompanyTable() {
return (
<DataTable
records={records}
columns={[
{ accessor: 'name', title: 'Company Name' },
{ accessor: 'city', title: 'City' },
{ accessor: 'employees', title: 'Employees', sortable: true },
]}
/>
);
}
補足
-
accessor: keyof Company
とできないのが制約ですが、補完はある程度効きます。 - より堅牢にしたい場合、accessorを
"name" as const
のように書くとミスが減ります。
3. mantine-react-table
における型定義(本格的)
ポイント
-
columns
とdata
の両方に同じ型を適用する。 - ジェネリクス(
<T>
)を明示すると型補完が強力に働きます。
型付き実装例(おすすめ構成)
import {
MantineReactTable,
MRT_ColumnDef,
useMantineReactTable,
} from 'mantine-react-table';
type User = {
firstName: string;
lastName: string;
age: number;
email: string;
};
const data: User[] = [
{ firstName: 'John', lastName: 'Doe', age: 28, email: 'john@example.com' },
{ firstName: 'Jane', lastName: 'Smith', age: 34, email: 'jane@example.com' },
];
// columns の型を明示する
const columns: MRT_ColumnDef<User>[] = [
{ accessorKey: 'firstName', header: 'First Name' },
{ accessorKey: 'lastName', header: 'Last Name' },
{ accessorKey: 'age', header: 'Age' },
{ accessorKey: 'email', header: 'Email' },
];
function UserTable() {
const table = useMantineReactTable<User>({
columns,
data,
enableSorting: true,
enablePagination: true,
});
return <MantineReactTable table={table} />;
}
補足
-
MRT_ColumnDef<User>[]
のように型をつけることで、accessorKey
に typo があるとコンパイルエラーになります。 - より厳密に扱いたい場合は、
useMemo
でcolumns
を囲むとパフォーマンスも向上します。
比較表
コンポーネント | 型付け方法の例 | 型安全性 | 自動補完 | コメント |
---|---|---|---|---|
@mantine/core Table |
配列に型付け (type Row ) |
◎ | ◎ | すべて手動なので自由だが責任も伴う |
@mantine/datatable |
records: 型[] |
○ | △ |
accessor は string 扱いで注意が必要 |
mantine-react-table |
<T> に型定義、ColumnDef使用 |
◎ | ◎ | タイポ防止・コンパイルでの型検査が強力 |