Implementation with Claude Code
Learn about implementation using Claude Code. Practical tips and code examples included.
テーブルコンポーネントの要件
データテーブルは管理画面やダッシュボードの中心的なUIです。ソート、フィルター、ページネーション、列のリサイズなど多くの機能が求められます。Claude Codeを使えば、TanStack Tableをベースに高機能なテーブルを素早く構築できます。
TanStack Tableによる基本実装
> TanStack Tableを使ったソート・フィルター付きテーブルを作って。
> 型安全で、カラム定義を宣言的に書けるようにして。
import {
useReactTable, getCoreRowModel, getSortedRowModel,
getFilteredRowModel, getPaginationRowModel,
flexRender, createColumnHelper, SortingState,
} from '@tanstack/react-table';
import { useState } from 'react';
interface User {
id: string;
name: string;
email: string;
role: string;
createdAt: string;
}
const columnHelper = createColumnHelper<User>();
const columns = [
columnHelper.accessor('name', {
header: '名前',
cell: (info) => <span className="font-medium">{info.getValue()}</span>,
}),
columnHelper.accessor('email', {
header: 'メールアドレス',
}),
columnHelper.accessor('role', {
header: '権限',
cell: (info) => (
<span className={`px-2 py-1 rounded text-xs ${
info.getValue() === 'admin' ? 'bg-red-100 text-red-700' : 'bg-gray-100'
}`}>
{info.getValue()}
</span>
),
}),
columnHelper.accessor('createdAt', {
header: '登録日',
cell: (info) => new Date(info.getValue()).toLocaleDateString('en-US'),
}),
];
function DataTable({ data }: { data: User[] }) {
const [sorting, setSorting] = useState<SortingState>([]);
const [globalFilter, setGlobalFilter] = useState('');
const table = useReactTable({
data,
columns,
state: { sorting, globalFilter },
onSortingChange: setSorting,
onGlobalFilterChange: setGlobalFilter,
getCoreRowModel: getCoreRowModel(),
getSortedRowModel: getSortedRowModel(),
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
});
return (
<div>
<input
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
placeholder="検索..."
className="mb-4 px-3 py-2 border rounded w-full max-w-sm"
/>
<table className="w-full border-collapse" role="grid">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
className="px-4 py-3 text-left bg-gray-50 border-b cursor-pointer select-none"
aria-sort={header.column.getIsSorted() === 'asc' ? 'ascending' : header.column.getIsSorted() === 'desc' ? 'descending' : 'none'}
>
{flexRender(header.column.columnDef.header, header.getContext())}
{{ asc: ' ↑', desc: ' ↓' }[header.column.getIsSorted() as string] ?? ''}
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((row) => (
<tr key={row.id} className="hover:bg-gray-50">
{row.getVisibleCells().map((cell) => (
<td key={cell.id} className="px-4 py-3 border-b">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<Pagination table={table} />
</div>
);
}
ページネーション
function Pagination({ table }: { table: any }) {
return (
<div className="flex items-center justify-between mt-4">
<span className="text-sm text-gray-500">
全{table.getFilteredRowModel().rows.length}件中{' '}
{table.getState().pagination.pageIndex * table.getState().pagination.pageSize + 1}〜
{Math.min(
(table.getState().pagination.pageIndex + 1) * table.getState().pagination.pageSize,
table.getFilteredRowModel().rows.length
)}件
</span>
<div className="flex gap-2">
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}
className="px-3 py-1 border rounded disabled:opacity-50">Previous</button>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}
className="px-3 py-1 border rounded disabled:opacity-50">Next</button>
</div>
</div>
);
}
行選択と一括操作
const [rowSelection, setRowSelection] = useState({});
// テーブル設定に追加
const table = useReactTable({
// ...既存の設定
state: { sorting, globalFilter, rowSelection },
onRowSelectionChange: setRowSelection,
enableRowSelection: true,
});
// 一括操作ボタン
const selectedCount = Object.keys(rowSelection).length;
{selectedCount > 0 && (
<div className="mb-4 p-3 bg-blue-50 rounded flex items-center gap-4">
<span>{selectedCount}件選択中</span>
<button onClick={() => handleBulkDelete(table.getSelectedRowModel().rows)}>
一括Delete
</button>
</div>
)}
Summary
Claude Codeを使えば、TanStack Tableベースの高機能テーブルをソート・フィルター・ページネーション付きで素早く構築できます。データの可視化はデータ可視化の記事を、カレンダー表示はカレンダーコンポーネントを参照してください。
TanStack Tableの詳細はTanStack Table公式ドキュメントをご覧ください。
Level up your Claude Code workflow
50 battle-tested prompt templates you can copy-paste into Claude Code right now.
Free PDF: Claude Code Cheatsheet in 5 Minutes
Key commands, shortcuts, and prompt examples on a single printable page.
About the Author
Masa
Engineer obsessed with Claude Code. Runs claudecode-lab.com, a 10-language tech media with 2,000+ pages.
Related Posts
Creating Custom Slash Commands in Claude Code — Tailor Your Workflow
Learn how to create custom slash commands in Claude Code. Covers file placement, arguments, and automating frequent tasks with practical code examples.
10 Tips to Triple Your Productivity with Claude Code
Learn about 10 tips to triple your productivity using Claude Code. Practical tips and code examples included.
Canvas/WebGL Optimization with Claude Code
Learn about Canvas/WebGL optimization using Claude Code. Practical tips and code examples included.