データグリッドライブラリ比較

3つのアプローチで編集可能なデータグリッドを実装し、機能とスタイルを比較

共通のサンプルデータ

社員情報テーブルを共通データとして使用しています。各デモではセルをダブルクリック(AG Gridはシングルクリック)して編集できます。

[
  {
    "name": "田中太郎",
    "department": "エンジニアリング",
    "position": "シニアエンジニア",
    "salary": 7500000
  },
  {
    "name": "佐藤花子",
    "department": "デザイン",
    "position": "UIデザイナー",
    "salary": 6000000
  },
  {
    "name": "鈴木一郎",
    "department": "エンジニアリング",
    "position": "テックリード",
    "salary": 9000000
  }
]

... 他 5

1. AG Grid Community

業界標準のエンタープライズグリッド — ソート、フィルタ、セル編集などが内蔵

特徴

  • • セルクリックで即座にインライン編集が可能
  • • ソート・フィルタ・カラムリサイズが標準搭載
  • • 大量データ(数万行)でも高速な仮想スクロール
  • • Community版は無料、Enterprise版は有料機能あり

インストール

npm install ag-grid-react ag-grid-community
tsx
'use client';
import { AgGridReact } from 'ag-grid-react';
import { AllCommunityModule, ModuleRegistry, type ColDef } from 'ag-grid-community';
import { useState, useMemo } from 'react';

ModuleRegistry.registerModules([AllCommunityModule]);

interface Employee {
  id: number;
  name: string;
  department: string;
  salary: number;
}

const rowData: Employee[] = [
  { id: 1, name: '田中太郎', department: 'エンジニアリング', salary: 7500000 },
  { id: 2, name: '佐藤花子', department: 'デザイン', salary: 6000000 },
  { id: 3, name: '鈴木一郎', department: 'マーケティング', salary: 5500000 },
];

export function AgGridDemo() {
  const columnDefs = useMemo<ColDef<Employee>[]>(() => [
    { field: 'id', headerName: 'ID', width: 80 },
    { field: 'name', headerName: '氏名', editable: true },
    { field: 'department', headerName: '部署', editable: true },
    {
      field: 'salary',
      headerName: '年収',
      editable: true,
      valueFormatter: p => `¥${p.value.toLocaleString()}`,
    },
  ], []);

  const defaultColDef = useMemo(() => ({
    sortable: true,
    filter: true,
    resizable: true,
  }), []);

  return (
    <div className="ag-theme-alpine" style={{ height: 300, width: '100%' }}>
      <AgGridReact rowData={rowData} columnDefs={columnDefs} defaultColDef={defaultColDef} />
    </div>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、AG Grid Communityを使った編集可能なデータグリッドを実装してください。
- 使用ライブラリ: ag-grid-react、ag-grid-community(AllCommunityModule、ModuleRegistry)
- AgGridReact コンポーネントと ColDef 型を使ってカラム定義を行うこと
- editable: true でセルをクリックしてインライン編集できること
- defaultColDef に sortable: true、filter: true、resizable: true を設定すること
- valueFormatter でサラリー列を¥形式で書式化すること
- onCellValueChanged コールバックで編集後のデータを state に反映すること
- ag-theme-alpine クラスでスタイルを適用すること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

2. TanStack Table(React Table v8)

ヘッドレスUIライブラリ — ロジックのみ提供し、表示は完全にカスタム可能

ID氏名部署役職メール年収入社日
1田中太郎エンジニアリングシニアエンジニアtanaka@example.com¥7,500,0002020-04-01
2佐藤花子デザインUIデザイナーsato@example.com¥6,000,0002021-07-15
3鈴木一郎エンジニアリングテックリードsuzuki@example.com¥9,000,0002019-01-10
4高橋美咲マーケティングマーケターtakahashi@example.com¥5,500,0002022-03-20
5伊藤健太エンジニアリングフロントエンドエンジニアito@example.com¥6,500,0002021-11-01
6渡辺真理人事HRマネージャーwatanabe@example.com¥7,000,0002018-06-01
7山本大輔デザインプロダクトデザイナーyamamoto@example.com¥6,800,0002020-09-15
8中村さくらマーケティングコンテンツディレクターnakamura@example.com¥6,200,0002022-01-10

セルをダブルクリックで編集(IDは編集不可)

特徴

  • • ヘッドレスUIでスタイルに完全な自由度
  • • ソート・フィルタ・ページネーションのロジックを提供
  • • バンドルサイズが非常に小さい(~15KB gzipped)
  • • TypeScript ファーストで型安全

インストール

npm install @tanstack/react-table
tsx
'use client';
import {
  useReactTable,
  getCoreRowModel,
  flexRender,
  type ColumnDef,
} from '@tanstack/react-table';
import { useMemo } from 'react';

interface Employee {
  id: number;
  name: string;
  department: string;
  salary: number;
}

const data: Employee[] = [
  { id: 1, name: '田中太郎', department: 'エンジニアリング', salary: 7500000 },
  { id: 2, name: '佐藤花子', department: 'デザイン', salary: 6000000 },
  { id: 3, name: '鈴木一郎', department: 'マーケティング', salary: 5500000 },
];

export function TanStackTableDemo() {
  const columns = useMemo<ColumnDef<Employee>[]>(() => [
    { accessorKey: 'id', header: 'ID' },
    { accessorKey: 'name', header: '氏名' },
    { accessorKey: 'department', header: '部署' },
    {
      accessorKey: 'salary',
      header: '年収',
      cell: info => `¥${info.getValue<number>().toLocaleString()}`,
    },
  ], []);

  const table = useReactTable({ data, columns, getCoreRowModel: getCoreRowModel() });

  return (
    <div className="overflow-x-auto border border-gray-200 rounded-lg">
      <table className="w-full text-sm">
        <thead>
          {table.getHeaderGroups().map(hg => (
            <tr key={hg.id} className="bg-gray-100 border-b border-gray-200">
              {hg.headers.map(h => (
                <th key={h.id} className="text-left px-3 py-2.5 font-semibold text-gray-700">
                  {flexRender(h.column.columnDef.header, h.getContext())}
                </th>
              ))}
            </tr>
          ))}
        </thead>
        <tbody>
          {table.getRowModel().rows.map(row => (
            <tr key={row.id} className="border-b border-gray-100 hover:bg-blue-50">
              {row.getVisibleCells().map(cell => (
                <td key={cell.id} className="px-3 py-2">
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、TanStack Table(@tanstack/react-table)を使った編集可能なデータグリッドを実装してください。
- 使用ライブラリ: @tanstack/react-table(useReactTable、getCoreRowModel、flexRender、ColumnDef)
- ColumnDef 型でカラム定義し、useReactTable フックでテーブルを構築すること
- セルをダブルクリックしてインライン編集できること(IDカラムは編集不可)
- 編集中のセルは input 要素に切り替え、Enter/Escape/blur で確定・キャンセルすること
- 数値列(salary)は入力時に number 型の input を使用すること
- getHeaderGroups、getRowModel を使ってヘッダーと行をレンダリングすること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

3. カスタム実装(React + Tailwind CSS)

ライブラリ不要の完全カスタム実装 — 行の追加・削除・ソートも自作

ID氏名部署役職メール年収入社日
1田中太郎エンジニアリングシニアエンジニアtanaka@example.com¥7,500,0002020-04-01
2佐藤花子デザインUIデザイナーsato@example.com¥6,000,0002021-07-15
3鈴木一郎エンジニアリングテックリードsuzuki@example.com¥9,000,0002019-01-10
4高橋美咲マーケティングマーケターtakahashi@example.com¥5,500,0002022-03-20
5伊藤健太エンジニアリングフロントエンドエンジニアito@example.com¥6,500,0002021-11-01
6渡辺真理人事HRマネージャーwatanabe@example.com¥7,000,0002018-06-01
7山本大輔デザインプロダクトデザイナーyamamoto@example.com¥6,800,0002020-09-15
8中村さくらマーケティングコンテンツディレクターnakamura@example.com¥6,200,0002022-01-10

ヘッダーをクリックでソート、セルをダブルクリックで編集

特徴

  • • 外部ライブラリ不要で依存関係が少ない
  • • 行の追加・削除・ソート・インライン編集を自作
  • • デザインの自由度が最も高い
  • • バンドルサイズへの影響が最小限

インストール

追加パッケージ不要(React + Tailwind CSS のみ)
tsx
'use client';
import { useState, useMemo } from 'react';

interface Employee {
  id: number;
  name: string;
  department: string;
  salary: number;
}

const initialData: Employee[] = [
  { id: 1, name: '田中太郎', department: 'エンジニアリング', salary: 7500000 },
  { id: 2, name: '佐藤花子', department: 'デザイン', salary: 6000000 },
  { id: 3, name: '鈴木一郎', department: 'マーケティング', salary: 5500000 },
];

export function CustomGridDemo() {
  const [data, setData] = useState(initialData);
  const [sortField, setSortField] = useState<keyof Employee | null>(null);
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');

  const sorted = useMemo(() => {
    if (!sortField) return data;
    return [...data].sort((a, b) => {
      const av = a[sortField], bv = b[sortField];
      if (typeof av === 'number' && typeof bv === 'number') return sortDir === 'asc' ? av - bv : bv - av;
      return sortDir === 'asc' ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
    });
  }, [data, sortField, sortDir]);

  const handleSort = (field: keyof Employee) => {
    if (sortField === field) setSortDir(d => d === 'asc' ? 'desc' : 'asc');
    else { setSortField(field); setSortDir('asc'); }
  };

  return (
    <div className="overflow-x-auto border border-gray-200 rounded-lg">
      <table className="w-full text-sm">
        <thead>
          <tr className="bg-slate-700 text-white">
            {(['id', 'name', 'department', 'salary'] as (keyof Employee)[]).map(key => (
              <th
                key={key}
                className="text-left px-3 py-2.5 font-semibold cursor-pointer hover:bg-white/10"
                onClick={() => handleSort(key)}
              >
                {key} {sortField === key ? (sortDir === 'asc' ? '▲' : '▼') : ''}
              </th>
            ))}
          </tr>
        </thead>
        <tbody>
          {sorted.map((row, i) => (
            <tr key={row.id} className={`border-b border-gray-100 ${i % 2 === 0 ? 'bg-white' : 'bg-gray-50'}`}>
              <td className="px-3 py-2">{row.id}</td>
              <td className="px-3 py-2">{row.name}</td>
              <td className="px-3 py-2">{row.department}</td>
              <td className="px-3 py-2">¥{row.salary.toLocaleString()}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

🤖 AIプロンプトテンプレート

React + Tailwind CSSで、ライブラリ不要のカスタムデータグリッドを実装してください。
- 使用ライブラリ: React + Tailwind CSS のみ(外部グリッドライブラリなし)
- セルをダブルクリックしてインライン編集できること(IDカラムは編集不可)
- 列ヘッダーをクリックで昇順・降順ソートできること(useMemo でソート済みデータを計算)
- 行の追加・削除ができること
- 数値列は¥形式で書式化して表示すること
- ソート中のカラムには▲▼アイコンを表示すること
- 偶数・奇数行で背景色を交互に変えるゼブラストライプを実装すること

⚠️ このプロンプトはあくまでたたき台です。AIの回答はモデルやバージョン、会話の文脈によって毎回異なります。意図通りに動かない場合は、条件を追記・修正してお使いください。

ライブラリ比較表

項目AG GridTanStack Tableカスタム実装
インライン編集内蔵(高機能)自作(ロジック支援あり)自作
ソート内蔵プラグイン提供自作
フィルタ内蔵(多種)プラグイン提供自作
仮想スクロール内蔵外部ライブラリ併用自作(複雑)
バンドルサイズ大きめ(~300KB)小さい(~15KB)最小
学習コスト中〜高低〜高(要件次第)
カスタマイズ性中(テーマ・API)高(ヘッドレス)最高
おすすめ用途業務アプリ・管理画面独自デザインのテーブルシンプルな要件

まとめ

AG Grid — 業務アプリや管理画面など、大量データを扱う本格的なデータグリッドが必要な場合に最適。ソート・フィルタ・編集・仮想スクロールがすべて内蔵されている。

TanStack Table — 独自のデザインシステムに合わせたテーブルを構築したい場合におすすめ。ロジックだけを提供するヘッドレス設計で、UIの自由度が高い。

カスタム実装 — シンプルな要件やプロトタイプに最適。ライブラリ依存がなく、必要な機能だけを実装できる。