data-table-filters について
フィルター、ソート、無限スクロール、仮想化に対応したデータテーブルを構築する、shadcn のレジストリです。開発者はスキーマ推論やサーバーサイド連携などの機能を必要に応じて追加できます。
主な機能
- 01組み合わせ可能なテーブルブロック
- 02組み込みの4種類のフィルター
- 03無限スクロールと仮想化
- 04JSONからのスキーマ推論
- 05URLとクライアント状態のアダプター
- 06オプションのAI・MCPブロック
活用シーン
- 01フィルターと無限スクロール付きログビューアーの構築
- 02JSONデータから列とフィルターを推論
- 03Drizzle ORMまたはReact Queryとの連携
- 04自然言語フィルターやMCPエンドポイントの追加
MCP 対応
オプションの data-table-mcp ブロックは、AIエージェント向けにステートレスでサーバーレス対応の MCP サーバーエンドポイントを提供します。
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ openstatushq/ data-table-filters --skill data-table-filtersインストール後、Claude Code で/data-table-filtersを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/ai-filters.mdauto-infer.mdcomponent-catalog.mddrizzle-integration.mdfetch-layer.mdmcp-server.mdschema-api.mdstore-adapters.mdscripts/detect-stack.sh詳細
データテーブルのフィルター
無限スクロールと仮想化に対応した、フィルターおよびソート可能なデータテーブルを構築するための shadcn レジストリです。コアブロックから始め、コマンドパレット、セルレンダラー、シートパネル、ストアアダプター、スキーマ生成、Drizzle ORM ヘルパー、React Query 連携のオプションブロックを追加して拡張できます。
前提条件。 どちらの shadcn ライブラリでも動作します。CLI のデフォルトである Base UI(
npx shadcn@latest init -d)または Radix(npx shadcn@latest init -b radix -p lyra)に対応しています。CI では両方にインストールして、レジストリの変更ごと、および毎晩、型チェックを実行します。
レジストリブロック
npx shadcn@latest add @data-table-filters/<block> を使って、任意のブロックをインストールできます。CLI が依存関係、パスの書き換え、CSS 変数の挿入を処理します。
| ブロック | インストール | 追加されるもの |
|---|---|---|
| data-table | @data-table-filters/data-table | コア機能:テーブルエンジン、ストア、4 種類のフィルター、メモリーアダプター(63 ファイル) |
| data-table-filter-command | @data-table-filters/data-table-filter-command | 履歴とキーボードショートカットを備えたコマンドパレット |
| data-table-cell | @data-table-filters/data-table-cell | 12 種類のセルレンダラー(テキスト、コード、数値、バー、ヒートマップ、ゲージ、バッジ、ブール値、星、ステータスコード、レベルインジケーター、タイムスタンプ) |
| data-table-sheet | @data-table-filters/data-table-sheet | 行の詳細を表示するサイドパネル(セルを自動インストール) |
| data-table-nuqs | @data-table-filters/data-table-nuqs | nuqs URL 状態アダプター |
| data-table-zustand | @data-table-filters/data-table-zustand | zustand 状態アダプター |
| data-table-schema | @data-table-filters/data-table-schema | col.* ファクトリーを備えた宣言型スキーマシステム |
| data-table-drizzle | @data-table-filters/data-table-drizzle | Drizzle ORM のサーバーサイドヘルパー(スキーマを自動インストール) |
| data-table-query | @data-table-filters/data-table-query | React Query の無限クエリ統合 |
| data-table-filter-command-ai | @data-table-filters/data-table-filter-command-ai | AI を活用した自然言語からのフィルター推論(プロバイダーに依存しません) |
| data-table-mcp | @data-table-filters/data-table-mcp | AI エージェント向け MCP サーバーエンドポイント(ステートレス、サーバーレス対応) |
| data-table-actions | @data-table-filters/data-table-actions | サーバーメタデータから表示する行および一括アクション(drizzle が必要) |
| data-table-remote | @data-table-filters/data-table-remote | エンドポイントのマニフェスト(スキーマ、機能、行の識別情報)を基に動作するヘッドレステーブル |
| data-table-chart | @data-table-filters/data-table-chart | テーブル上のタイムラインチャート:レベルごとの積み上げバケット、ドラッグによる時間フィルターのズーム |
| data-table-example-infinite | @data-table-filters/data-table-example-infinite | すぐに実行できる /example ルート:スキーマ、モック API、URL 状態を備えた無限テーブル |
ブロックは shadcn レジストリディレクトリから名前でインストールできます。JSON 形式の https://data-table.openstatus.dev/r/<block>.json も使用できます。
クイックスタート
scripts/detect-stack.shを実行して、ユーザーのプロジェクト設定を検出します。プロジェクトが使用しているコンポーネントライブラリが表示されます。どちらを使っても問題ありません。shadcn/ui: not initializedと表示された場合は、先にnpx shadcn@latest init -d(Radix の場合はinit -b radix -p lyra)で初期化してから続行してください。まだプロジェクトがありませんか?pnpm dlx shadcn@latest init @data-table-filters/data-table-example-infinite --name logs-viewer --template next -p lyraを実行すると、shadcn が初期化され、必要なブロックがすべてインストールされた動作する/exampleルート(タイムラインチャート、フィルター、無限スクロール、行シート)を備えた Next.js アプリが作成されます(Radix の場合は-p lyraの前に-b radixを追加してください)。pnpm が必要です(npm i -g pnpm)。npm を使う場合も、npxとnpm run devは同じように使用できます。その後、cd logs-viewerを実行して開発サーバーを起動し、http://localhost:3000/example を開いてapp/example/table-schema.tsを編集するか、手順 2 に進んで独自のテーブルを作成してください。- コアとスキーマをインストールします:
npx shadcn@latest add @data-table-filters/data-table @data-table-filters/data-table-schema - 最小限の動作するテーブルをセットアップします(下記を参照)。データの形状が不明な場合は
<DataTableAuto data={rows} />をレンダリングします - 必要に応じて追加ブロックで拡張します
Next.js をお使いですか? data-table-filters repo を参考にしてください。すべてのブロックが接続された完全な Next.js アプリです。
最小限の動作するテーブル(メモリアダプター)
注:
DataTableInfiniteは内部でDataTableProviderをレンダリングし、すでに子要素をControlsProviderとDataTableStoreSyncでラップしています。これらを個別に追加する必要はありません。必要なラッパーはDataTableStoreProvider(BYOS アダプター用)のみです。
"use client";
import { DataTableInfinite } from "@/components/data-table/data-table-infinite";
import type { DataTableFilterField } from "@/components/data-table/types";
import { useMemoryAdapter } from "@/lib/store/adapters/memory";
import { DataTableStoreProvider } from "@/lib/store/provider/DataTableStoreProvider";
import type { ColumnDef } from "@tanstack/react-table";
const columns: ColumnDef<YourData>[] = [
/* user's columns */
];
const filterFields: DataTableFilterField<YourData>[] = [
/* user's filters */
];
export function MyTable({ data }: { data: YourData[] }) {
const adapter = useMemoryAdapter(/* schema definition */);
return (
<DataTableStoreProvider adapter={adapter}>
<DataTableInfinite
columns={columns}
data={data}
filterFields={filterFields}
/>
</DataTableStoreProvider>
);
}
拡張ブロックの接続
npx shadcn@latest add でブロックをインストールした後、テーブルに接続します。
コマンドパレット → commandSlot
<DataTableInfinite
commandSlot={<DataTableFilterCommand schema={schema} tableId="my-table" />}
/>
シート詳細パネル → sheetSlot
<DataTableInfinite
sheetSlot={
<DataTableSheetDetails title="Details">{content}</DataTableSheetDetails>
}
/>
フローティングバー(一括操作)→ floatingBarSlot
スキーマに col.select() を追加すると、チェックボックスによる複数行選択が有効になります。アクションは DataTableFloatingBar でラップします。選択状態はコンテキストから読み取られます(sheetSlot における DataTableSheetDetails と同じパターンです)。
// In table-schema.tsx
export const tableSchema = createTableSchema({
select: col.select().size(37),
// ... other columns
});
// In client.tsx
import { DataTableFloatingBar } from "@/components/data-table/data-table-floating-bar";
<DataTableInfinite
floatingBarSlot={
<DataTableFloatingBar>
{({ rows }) => (
<Button variant="outline" size="sm" onClick={() => console.log(rows)}>
Export ({rows.length})
</Button>
)}
</DataTableFloatingBar>
}
/>;
行アクション → data-table-actions
インストール:npx shadcn@latest add @data-table-filters/data-table-actions(drizzle ブロックが必要です)。
アクションは、Drizzle ハンドラーの隣にサーバー側で一度だけ宣言します。リストエンドポイントはアクションを公開し(meta.actions)、該当する ID を各行に付与します(_actions)。UI はその JSON を使って表示し、アクションの内容を知ることはありません。
// app/<table>/api/actions.ts
export const actionHandler = createActionHandler({
db,
table,
filters,
columnMapping, // same as createDrizzleHandler, plus the id column
idColumn: "uuid",
basePath: "/<table>/api/actions",
actions: {
acknowledge: {
label: "Acknowledge",
scope: ["row", "bulk", "filter"],
when: { level: ["error"] }, // filter values — evaluated in JS for _actions, compiled to SQL as the WHERE guard
handler: async (ctx, tx) =>
(
await tx
.update(table)
.set({ level: "warning" })
.where(ctx.where)
.returning()
).length,
},
},
});
// GET route: data = actionHandler.annotate(result.data); meta.actions = actionHandler.descriptors
// POST app/<table>/api/actions/[id]/route.ts: actionHandler.execute(id, await req.json(), { actor })
// client.tsx
<DataTableActionsProvider
actions={meta?.actions}
getRowId={(r) => r.uuid}
queryKeyPrefix="<prefix>"
>
<DataTableInfinite
columns={[...generateColumns(schema), createActionsColumn()]}
floatingBarSlot={
<DataTableFloatingBar>
{({ rows }) => <DataTableActionsBar rows={rows} />}
</DataTableFloatingBar>
}
/>
</DataTableActionsProvider>
_actions はヒントです。実際の適用範囲はハンドラーの ctx.where(ID ∩ when)によって決まるため、applied は送信された ID の数を下回る場合があります。アクションはキューに追加されます(ステータスを切り替えます)が、実行はされません。結果は sonner のトーストで通知されます。レイアウトで <Toaster /> を一度だけマウントしてください(npx shadcn@latest add sonner)。
セルレンダラー → 列定義
import { DataTableCellBadge } from "@/components/data-table/data-table-cell";
// Use in columnDef.cell
カスタムフィルタータイプ → FILTER_COMPONENTS
4 種類のフィルタータイプはすべてコアに含まれています。カスタムタイプを追加するには:
import { FILTER_COMPONENTS } from "@/components/data-table/data-table-filter-controls";
FILTER_COMPONENTS.myCustom = MyCustomFilterComponent;
AI コマンドパレット → commandSlot
AI の結果をストリーミングする API ルートが必要です。references/ai-filters.md を参照してください。
<DataTableInfinite
commandSlot={
<DataTableFilterAICommand
schema={filterSchema.definition}
tableSchema={tableSchema.definition}
api="/api/ai-filters"
tableId="my-table"
/>
}
/>
すべてのスロットプロパティ
DataTableInfinite は commandSlot、sheetSlot、toolbarActions、chartSlot、footerSlot、floatingBarSlot を受け付けます。
接続方法の詳細は references/component-catalog.md を参照してください。
ストアアダプターの設定
- memory(デフォルト)— 一時的で、設定不要です。プロトタイピング、埋め込みコンポーネント、ビルダーに適しています。
- nuqs — URL 状態を管理します。共有可能なリンクやブックマーク可能なフィルターを利用できます。フレームワークのセットアップが必要です。
- zustand — クライアント状態を管理します。既存の zustand アプリや複雑なアプリ状態に適しています。
アダプターブロックをインストールし、プロバイダーを差し替えてください。references/store-adapters.md を参照してください。
スキーマ生成
インストール:npx shadcn@latest add @data-table-filters/data-table-schema
データモデルを createTableSchema + col.* にマッピングします:
-
string→col.string().filterable("input") -
number→col.number().filterable("slider", { min, max }) -
boolean→col.boolean().filterable("checkbox") -
Date→col.timestamp().filterable("timerange") -
enum→col.enum(values).filterable("checkbox") -
select→col.select()(チェックボックスによる行選択。フィルターには使用できません)
プリセット:col.presets.logLevel()、.httpStatus()、.duration()、.timestamp()、.traceId()、.pathname()、.httpMethod()。
references/schema-api.md を参照してください。
自動推論(JSON からのゼロ設定)
事前定義されたスキーマのない生の JSON データには、DataTableAuto または低レベルの inferSchemaFromJSON + createTableSchema.fromJSON パイプラインを使用します。データ自体から列、フィルター、シートのフィールド、列の表示設定を自動生成します。
DataTableAuto コンポーネント
そのまま使えるコンポーネントです。JSON データを渡すだけで、完全に機能するテーブルが得られます:
import { DataTableAuto } from "@/components/data-table/data-table-auto";
import data from "./data.json";
export default function Page() {
return <DataTableAuto data={data} />;
}
コマンドパレットとシート詳細パネルがあらかじめ含まれています。動作例は、このリポジトリの /auto ルートを参照してください。
低レベル API
import { inferSchemaFromJSON } from "@/lib/table-schema/infer";
import { createTableSchema } from "@/lib/table-schema";
const schemaJson = inferSchemaFromJSON(data);
const { definition } = createTableSchema.fromJSON(schemaJson);
推論のヒューリスティクス、スマートな拡張、カスタマイズについては、references/auto-infer.md を参照してください。
サーバーサイド統合
インストール:npx shadcn@latest add @data-table-filters/data-table-drizzle
createDrizzleHandler({ db, table, columnMapping, cursorColumn, schema }) でルートハンドラーを生成します。
Drizzle 以外の ORM では、レスポンス形式 { data, facets, totalRowCount, filterRowCount, nextCursor, prevCursor } を実装してください。
references/drizzle-integration.md を参照してください。
フェッチ層
インストール:npx shadcn@latest add @data-table-filters/data-table-query
createDataTableQueryOptions({ queryKeyPrefix, apiEndpoint, searchParamsSerializer }) を接続します。
デフォルトでは、同一オリジンへの fetch と SuperJSON のボディを使用します。他の API を使用する場合は、transport(baseUrl、同期/非同期関数としての headers、credentials、parseResponse)と、ページネーション方式(timestampCursorPagination()(デフォルト、双方向)、opaqueCursorPagination()、または offsetPagination({ size }))を指定します。schemaJsonParser(schema) はプレーンな ISO 文字列からタイムスタンプ列を復元するため、エンドポイントで SuperJSON を採用する必要はありません。2xx 以外のステータス、または解析できないボディの場合、status、url、ボディのスニペットを含む DataTableFetchError がスローされます。
references/fetch-layer.md を参照してください。
ヘッドレステーブル(エンドポイントを指定)
インストール:npx shadcn@latest add @data-table-filters/data-table-remote
データとエンドポイントを別の場所で管理するテーブル向けで、アプリ側で列ごとのコードを記述する必要はありません。
サーバー — テーブルを説明するマニフェストを公開します:
// app/<table>/api/schema/route.ts
const handler = createTableManifestHandler(
createTableManifest({
schema: tableSchema,
primaryKey: "uuid", // the column that identifies a row on the wire
rowLabel: "{method} {pathname}", // template over column keys, for a11y
capabilities: { facets: true, totalRowCount: true, chart: true },
defaults: { sort: { id: "date", desc: true }, size: 40 },
}),
);
export const GET = (request: Request) => handler(request);
マニフェストがリクエストに依存する場合(テナントごとの列、権限に応じたアクションなど)は、値の代わりに関数を渡してください。ETag を付けて配信されるため、再検証時には 304 が返されます。
クライアント:
<DataTableRemote
manifestEndpoint="/logs/api/schema" // data endpoint defaults to this minus /schema
searchParamsSerializer={searchParamsSerializer}
initialManifest={snapshot} // optional — skips the round trip before first paint
transport={{ headers: async () => ({ authorization: await token() }) }}
renderers={{ pathname: { cell: (v) => <PathnameCell value={String(v)} /> } }}
/>
重要な点:
- 機能はデフォルトで無効です。 エンドポイントが実装している機能だけを宣言してください。未実装の機能がある場合、空の状態を表示するのではなく、テーブルは機能を縮退させます(クライアントサイドのファセット処理、空の件数、ライブボタンなし、チャートなし)。
- レンダラーはシリアライズされません。 名前付き表示(
badge、bar、status-codeなど)はデータとして渡されます。それ以外にはapplyRenderersまたはrenderersプロパティを使用してください。記述子は変更されないため、スキーマは引き続き往復変換できます。 - マニフェストは信頼できないものとして扱われます。 列とアクションの数には上限があります。アクションの
hrefは、allowedActionOriginsで許可リストに登録されていない限り、ページと同じオリジンに制限されます。 - 往復通信を避けるにはスナップショットを使用します。
pullManifestModule(url)は型付きモジュールを書き出します。これをinitialManifestとして渡してください。実行時の再検証は引き続き行われます。 - エンドポイントを検証するには
runEndpointConformance({ url, manifest })とformatConformanceReportを使用します。
トラブルシューティング
- CSS 変数が不足している:Core は
--color-success/warning/error/infoを注入します。cssVars が CSS に適用されているか確認してください。 - インポートパスが一致しない:shadcn CLI は
components.jsonのエイリアスに従って@/パスを書き換えます。 - nuqs:何も起きない、またはクラッシュする:必須のセットアップ手順が 2 つあります。ルートレイアウトに
<NuqsAdapter>を配置し、テーブルコンポーネントを<Suspense>で囲んでください。references/store-adapters.md を参照してください。 - nuqs:読み込み時に URL のフィルターが適用されない:サーバーで解析した検索パラメーターを
initialStateとして nuqs アダプターに渡してください。references/store-adapters.md の SSR ハイドレーションのセクションを参照してください。 - nuqs:空文字列でフィルターが意図せず表示される:
field.string().default("")ではなく、field.string()(デフォルト値は null)を使用してください。 - シートのドロップダウンが表示されない:フィルターのドロップダウンを表示するには、
SheetField.typeをフィルタータイプに一致させてください("readonly"は指定しないでください)。フィルター設定から自動的に導出するには、generateSheetFields()を使用してください。 - フィルターがレンダリングされない:フィルタータイプの文字列が
FILTER_COMPONENTSのキーと一致していることを確認してください。 - Tailwind v4:レジストリは v4 を対象としています。クラス構文は v3 と異なります。