Introduction
It’s not a library. It’s a playbook.
Stop hand-rolling data tables. Copy proven patterns, install the agent skill and start shipping.
Built on:
- shadcn registry — drop components directly into your codebase
- TanStack Table + Query — sorting, filtering, infinite scroll, done
- Drizzle ORM — server-side
WHERE, cursors, and faceted counts out of the box - nuqs / Zustand — URL or memory state, your call
- Agent SKILL.md — describe your schema, let the agent wire it up
Define a schema. Generate columns, filters, and sheet details. Done.


This guide covers the system end to end — from defining a table schema to rendering filters, columns, and row details. Get started with the Quick Start and jump to a Full Example.
Examples
- Auto — zero-config table from raw data (no schema needed)
- Drizzle — server-side filtering with Drizzle ORM
- Default — client-side pagination without infinite scroll
- Infinite — infinite scroll with cursor pagination (mock)
- Light — lightweight frontend for light.openstatus.dev
- Builder — interactive schema builder
Questions, ideas, or feedback? Open an issue on GitHub.
Quick Overview
Zero Config
Pass data, get a fully filtered table — columns, filters, and display types are auto-inferred:
import { DataTableAuto } from "@/components/data-table/data-table-auto";
<DataTableAuto data={bookmarks} />;See the /auto example for a live demo.
With Schema
When you need full control, define a schema and wire up state management:
import { col, createTableSchema } from "@/lib/table-schema";
import { generateColumns, generateFilterFields } from "@/lib/table-schema";
import { createSchema, field } from "@/lib/store/schema";
// 1. Define your table
const tableSchema = createTableSchema({
level: col.presets.logLevel(["error", "warn", "info", "debug"]),
latency: col.presets.duration("ms").label("Latency").sortable(),
host: col.string().label("Host"),
});
// 2. Generate everything the components need
const columns = generateColumns(tableSchema.definition);
const filterFields = generateFilterFields(tableSchema.definition);
// 3. Wire up state + components
<DataTableStoreProvider adapter={adapter}>
<DataTableInfinite columns={columns} filterFields={filterFields} ... />
</DataTableStoreProvider>Architecture
The data-table is built on three layers:
- Table Schema — a declarative builder that defines columns, filters, display, sorting, and row details in one place
- State Management — a pluggable adapter system for filter state (URL, Zustand, or custom)
- UI Components — pre-built filter controls, command palette, infinite scroll table, and row detail drawer
For server-side data, the Drizzle ORM helpers handle WHERE conditions, sorting, cursor pagination, and faceted counts. The Data Fetching layer covers the API response shape and React Query integration.
The schema is serializable, so it can also cross the network. Headless Tables inverts the first layer: instead of importing a schema, the table fetches one from an endpoint you own — along with what that endpoint can compute and what may be done to a row — and derives everything from it. You keep the data; the only thing you publish is its shape.
Table Schema → Generators → Components
↓ ↓ ↓
col.* columns[] DataTableInfinite
presets filterFields DataTableFilterControls
.sheet() sheetFields DataTableSheetDetails
filterSchema DataTableFilterCommand