tanstack-table
TanStack Tableは、Reactなど特定のフレームワークに依存せず、データの並び替え、絞り込み、ページ分割、列幅調整など、高度な機能を備えたデータテーブルを柔軟に構築できるSkill。
📜 元の英語説明(参考)
Build powerful data tables with TanStack Table — headless, framework-agnostic table library. Use when someone asks to "build a data table", "TanStack Table", "sortable table", "filterable data grid", "paginated table", "React table", or "headless table library". Covers sorting, filtering, pagination, column resizing, row selection, and virtualization.
🇯🇵 日本人クリエイター向け解説
TanStack Tableは、Reactなど特定のフレームワークに依存せず、データの並び替え、絞り込み、ページ分割、列幅調整など、高度な機能を備えたデータテーブルを柔軟に構築できるSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o tanstack-table.zip https://jpskill.com/download/15455.zip && unzip -o tanstack-table.zip && rm tanstack-table.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/15455.zip -OutFile "$d\tanstack-table.zip"; Expand-Archive "$d\tanstack-table.zip" -DestinationPath $d -Force; ri "$d\tanstack-table.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
tanstack-table.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
tanstack-tableフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
TanStack Table
概要
TanStack Table は、ヘッドレスなテーブルライブラリです。ロジック(ソート、フィルタリング、ページネーション、グループ化、列の表示/非表示)を処理し、レンダリングはユーザーが行います。定義済みのスタイルやマークアップはなく、テーブルの外観を完全に制御できます。React、Vue、Svelte、Solid、または vanilla JS で動作します。他の Material UI テーブルと似ていない、カスタムデータテーブルを構築するための標準です。
どのような時に使うか
- ソート、フィルタリング、ページネーションを備えた表形式のデータを表示する場合
- テーブルのスタイルを完全に制御する必要がある場合(事前スタイリングされたコンポーネントではない)
- サーバーサイドのページネーションとフィルタリング
- 列のサイズ変更、並べ替え、固定を伴う複雑なテーブル
- 行の選択と一括操作
- 仮想化されたレンダリングによる大規模なデータセット
手順
セットアップ
npm install @tanstack/react-table
基本的なテーブル
// components/DataTable.tsx — ソート、フィルタリング可能なテーブル
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
getFilteredRowModel,
getPaginationRowModel,
flexRender,
ColumnDef,
SortingState,
} from "@tanstack/react-table";
import { useState } from "react";
interface User {
id: number;
name: string;
email: string;
role: string;
status: "active" | "inactive";
joinedAt: string;
}
const columns: ColumnDef<User>[] = [
{
accessorKey: "name",
header: "Name",
cell: (info) => <span className="font-medium">{info.getValue<string>()}</span>,
},
{ accessorKey: "email", header: "Email" },
{ accessorKey: "role", header: "Role" },
{
accessorKey: "status",
header: "Status",
cell: (info) => (
<span className={info.getValue() === "active" ? "text-green-600" : "text-gray-400"}>
{info.getValue<string>()}
</span>
),
},
{
accessorKey: "joinedAt",
header: "Joined",
cell: (info) => new Date(info.getValue<string>()).toLocaleDateString(),
},
];
export function UsersTable({ 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>
{/* Search */}
<input
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
placeholder="Search all columns..."
className="mb-4 p-2 border rounded"
/>
{/* Table */}
<table className="w-full border-collapse">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
className="text-left p-3 border-b cursor-pointer hover:bg-gray-50"
>
{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="p-3 border-b">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
{/* Pagination */}
<div className="flex items-center gap-2 mt-4">
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Previous
</button>
<span>
Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
</span>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
Next
</button>
</div>
</div>
);
}
サーバーサイドのページネーション
// components/ServerTable.tsx — API からページごとにデータを取得
const table = useReactTable({
data: serverData.rows,
columns,
pageCount: serverData.pageCount,
state: { sorting, pagination },
onSortingChange: setSorting,
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
manualPagination: true, // サーバーがページネーションを処理
manualSorting: true, // サーバーがソートを処理
});
// ページネーション/ソートが変更されたときにフェッチ
useEffect(() => {
fetchData({
page: pagination.pageIndex,
pageSize: pagination.pageSize,
sortBy: sorting[0]?.id,
sortDir: sorting[0]?.desc ? "desc" : "asc",
});
}, [pagination, sorting]);
行の選択
const [rowSelection, setRowSelection] = useState({});
const columns: ColumnDef<User>[] = [
{
id: "select",
header: ({ table }) => (
<input type="checkbox" checked={table.getIsAllRowsSelected()} onChange={table.getToggleAllRowsSelectedHandler()} />
),
cell: ({ row }) => (
<input type="checkbox" checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} />
),
},
// ... その他の列
];
// 選択された行を取得
const selectedUsers = table.getSelectedRowModel().rows.map((r) => r.original);
例
例 1: CRUD を備えた管理者データテーブル
ユーザープロンプト: 「ユーザーを管理するための管理者テーブルを作成してください。ソート、フィルタリング、ページネーション、および一括削除を行います。」
エージェントは、すべての機能、一括操作のための行選択、および検索入力を持つ TanStack Table を作成します。
例 2: サーバーサイドでページネーションされたテーブル
ユーザープロンプト: 「私の API はページネーションされたデータを返します。ページごとにデータをフェッチするテーブルを作成してください。」
エージェントは手動ページを設定します
(原文がここで切り詰められています)
📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
TanStack Table
Overview
TanStack Table is a headless table library — it handles the logic (sorting, filtering, pagination, grouping, column visibility) and you handle the rendering. No predefined styles or markup, full control over how the table looks. Works with React, Vue, Svelte, Solid, or vanilla JS. The standard for building custom data tables that don't look like every other Material UI table.
When to Use
- Displaying tabular data with sorting, filtering, and pagination
- Need full control over table styling (not a pre-styled component)
- Server-side pagination and filtering
- Complex tables with column resizing, reordering, and pinning
- Row selection and bulk actions
- Large datasets with virtualized rendering
Instructions
Setup
npm install @tanstack/react-table
Basic Table
// components/DataTable.tsx — Sortable, filterable table
import {
useReactTable,
getCoreRowModel,
getSortedRowModel,
getFilteredRowModel,
getPaginationRowModel,
flexRender,
ColumnDef,
SortingState,
} from "@tanstack/react-table";
import { useState } from "react";
interface User {
id: number;
name: string;
email: string;
role: string;
status: "active" | "inactive";
joinedAt: string;
}
const columns: ColumnDef<User>[] = [
{
accessorKey: "name",
header: "Name",
cell: (info) => <span className="font-medium">{info.getValue<string>()}</span>,
},
{ accessorKey: "email", header: "Email" },
{ accessorKey: "role", header: "Role" },
{
accessorKey: "status",
header: "Status",
cell: (info) => (
<span className={info.getValue() === "active" ? "text-green-600" : "text-gray-400"}>
{info.getValue<string>()}
</span>
),
},
{
accessorKey: "joinedAt",
header: "Joined",
cell: (info) => new Date(info.getValue<string>()).toLocaleDateString(),
},
];
export function UsersTable({ 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>
{/* Search */}
<input
value={globalFilter}
onChange={(e) => setGlobalFilter(e.target.value)}
placeholder="Search all columns..."
className="mb-4 p-2 border rounded"
/>
{/* Table */}
<table className="w-full border-collapse">
<thead>
{table.getHeaderGroups().map((headerGroup) => (
<tr key={headerGroup.id}>
{headerGroup.headers.map((header) => (
<th
key={header.id}
onClick={header.column.getToggleSortingHandler()}
className="text-left p-3 border-b cursor-pointer hover:bg-gray-50"
>
{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="p-3 border-b">
{flexRender(cell.column.columnDef.cell, cell.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
{/* Pagination */}
<div className="flex items-center gap-2 mt-4">
<button onClick={() => table.previousPage()} disabled={!table.getCanPreviousPage()}>
Previous
</button>
<span>
Page {table.getState().pagination.pageIndex + 1} of {table.getPageCount()}
</span>
<button onClick={() => table.nextPage()} disabled={!table.getCanNextPage()}>
Next
</button>
</div>
</div>
);
}
Server-Side Pagination
// components/ServerTable.tsx — Fetch data per page from API
const table = useReactTable({
data: serverData.rows,
columns,
pageCount: serverData.pageCount,
state: { sorting, pagination },
onSortingChange: setSorting,
onPaginationChange: setPagination,
getCoreRowModel: getCoreRowModel(),
manualPagination: true, // Server handles pagination
manualSorting: true, // Server handles sorting
});
// Fetch when pagination/sorting changes
useEffect(() => {
fetchData({
page: pagination.pageIndex,
pageSize: pagination.pageSize,
sortBy: sorting[0]?.id,
sortDir: sorting[0]?.desc ? "desc" : "asc",
});
}, [pagination, sorting]);
Row Selection
const [rowSelection, setRowSelection] = useState({});
const columns: ColumnDef<User>[] = [
{
id: "select",
header: ({ table }) => (
<input type="checkbox" checked={table.getIsAllRowsSelected()} onChange={table.getToggleAllRowsSelectedHandler()} />
),
cell: ({ row }) => (
<input type="checkbox" checked={row.getIsSelected()} onChange={row.getToggleSelectedHandler()} />
),
},
// ... other columns
];
// Get selected rows
const selectedUsers = table.getSelectedRowModel().rows.map((r) => r.original);
Examples
Example 1: Admin data table with CRUD
User prompt: "Build an admin table for managing users — sort, filter, paginate, and bulk delete."
The agent will create a TanStack Table with all features, row selection for bulk actions, and a search input.
Example 2: Server-side paginated table
User prompt: "My API returns paginated data. Build a table that fetches page by page."
The agent will set up manual pagination/sorting, fetch data on state change, and handle loading states.
Guidelines
- Headless = you own the markup — style however you want
getCoreRowModelis required — always include it- Add models for features —
getSortedRowModel,getFilteredRowModel, etc. manualPaginationfor server-side — table tracks state, you fetch dataColumnDeffor type safety —accessorKeymaps to data fieldsflexRenderfor cell rendering — renders header and cell components- Row selection with
getToggleSelectedHandler— works with checkboxes - Column visibility —
table.getColumn("email")?.toggleVisibility(false) - Virtualization — combine with
@tanstack/react-virtualfor 100K+ rows - No styles included — use Tailwind, CSS, or any styling solution