CLI tool
openstatusHQ/data-table-filters avatar
openstatusHQ/data-table-filters

Fifteen shadcn blocks and one schema for React data tables

React data tables for shadcn/ui: faceted filters, sorting, infinite scroll. Filtering, faceted counts and cursor pagination can run in SQL with Drizzle.

2,283 stars137 forksTypeScriptMIT

At a glance

What is it?
data-table-filters copies table code into your app through the shadcn registry, and lets one schema drive filtering, faceted counts and cursor pagination. The cost is that nothing arrives as a pinned dependency, and two of its fifteen blocks ship without any setup detail.
Who is it for?
data-table-filters fits a team that already ships Next.js with shadcn/ui and wants faceted filters, counts and cursor pagination running in Postgres instead of in the browser. Pass on it if you need a pinned npm dependency, a non-Next framework, or a filter set that does not fit a declarative schema, because each block arrives as source you own and maintain.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 21 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One schema definition drives all fifteen blocks

data-table-filters is a set of React table components for shadcn/ui, and the shadcn registry is how they reach your project: the command `npx shadcn@latest add` copies source files into your repo instead of resolving a package from npm. Fifteen blocks are listed, running from the core `data-table` engine to optional pieces for cells, a row sheet, URL state, a timeline chart and an MCP endpoint. One `createTableSchema` call is the spine of it: the same definition feeds the columns, the filter controls, the row detail sheet, the Drizzle route handler and the MCP tool schema, so a field declared once shows up in the UI and in the server contract.

What the core block actually bundles is much narrower than a 15-entry block list: a table engine, a store, 4 filter types and a memory adapter. Those 4 filter types are counted but never named, so the four-way choice that drives your UI stays invisible until you read the docs site. Repository topics point at the surrounding machinery: cmdk for the command palette, nuqs for URL state, tanstack-react-query for server rows and tanstack-table for the table primitives underneath. The project was built for the openstatus dashboard and runs there in production, with full documentation hosted at data-table.openstatus.dev rather than in the repository.

Faceted counts and cursor pagination run in SQL

When rows live in Postgres, filtering, faceted counts and cursor pagination run in SQL rather than in the browser. The `@data-table-filters/data-table-drizzle` block supplies the server-side helpers, and the route handler is generated from the schema definition, so a filter added on the client side has a server counterpart to answer it.

Cursor pagination is the load-bearing choice. It returns a continuation point instead of a page number, which suits append-heavy tables such as log or event streams and avoids the drift that shows up when rows are inserted mid-scroll. `@data-table-filters/data-table-remote` takes the same idea one step further and renders from an API endpoint's manifest, so the table can live outside the app that owns the data.

What the repository does not show is the SQL itself. There is no generated query, no index advice, and no documented rule for what happens when a filter and a facet reference the same column, which is exactly the case where counts usually disagree with the visible rows.

Adding the core block through the shadcn registry

One command installs the table engine and the schema system together:

bash
npx shadcn@latest add @data-table-filters/data-table @data-table-filters/data-table-schema

Both shadcn libraries are supported: the CLI default, Base UI via `npx shadcn@latest init -d`, and Radix via `npx shadcn@latest init -b radix -p lyra`. CI installs the Quick Start into a fresh Next.js app on each library and typechecks them on every registry change, then again nightly against the latest shadcn CLI, so a new CLI version can break types in a copy that never changed. Blocks also resolve by JSON URL such as `https://data-table.openstatus.dev/r/<block>.json`, which matters when a corporate proxy blocks the registry host.

Behind the registry sits a pnpm and turbo monorepo. The root package is private at version 0.1.0, its scripts fan out through turbo for dev, build, lint, typecheck, test and registry:build, and packageManager pins [email protected]. A pnpm overrides block raises several transitive dependencies that a plain Next.js app would otherwise inherit:

json
"hono": ">=4.12.25",
"fast-uri": "^3.1.4",
"sharp": "^0.35.0",
"postcss@8": "^8.5.18",
"lodash": "^4.18.0",
"js-yaml@4": "^4.3.0"

Those floors live in the project's own workspace, not in the files it copies into your repo, so a security-motivated bump to hono or sharp has to be repeated downstream by hand. Workspace tooling is pinned as well: turbo 2.5.4, prettier 3.5.3, prettier-plugin-tailwindcss 0.7.2 and @ianvs/prettier-plugin-sort-imports 4.4.1. The copied code is MIT licensed. The last push to the repository was on 2026-09-20.

Rendering a first table from a plain array

Once the blocks are in place, the shortest real use is a component that reads an array of objects and infers columns, filters and cell renderers from its shape:

tsx
import { DataTableAuto } from "@/components/data-table/data-table-auto";

const data = [
  {
    name: "Alice",
    role: "admin",
    rating: 5,
    created_at: "2026-01-15T10:00:00Z",
  },
  { name: "Bob", role: "user", rating: 3, created_at: "2026-02-20T14:30:00Z" },
];

export default function Page() {
  return <DataTableAuto data={data} />;
}

`DataTableAuto` resolves to `@/components/data-table/data-table-auto`, a file the block wrote into your app rather than a package import, which is the clearest sign of the install-as-source model. Each object in that sample carries name, role, rating and created_at, with created_at held as an ISO string, so the timestamp renderer and the number renderer engage without a line of per-column configuration. Sorting, faceting and infinite scroll come with the core block, so the first screen is a working table rather than a skeleton.

The gap shows up on the next screen. Nothing documents how to override one inferred column without dropping to the declarative schema, and nothing states whether inference treats a numeric string as text or as a number, so a mixed dataset is something you verify by hand.

A standalone logs viewer from one scaffold command

To skip building an app by hand, the registry ships an example block that creates one for you:

bash
pnpm dlx shadcn@latest init @data-table-filters/data-table-example-infinite --name logs-viewer --template next -p lyra

That scaffolds the Next.js app, initializes shadcn, and drops in a `/example` route carrying its own schema, a mock API and an infinite table with URL state. Start it and the route answers on port 3000:

bash
cd logs-viewer && pnpm dev

Because that block uses a mock API, nothing in this path touches Postgres, which makes it the fastest way to see the component behaviour before committing to the SQL path.

Two details reward a close read. The scaffold command passes `-p lyra` without `-b radix`, so the generated example targets the CLI default library, and Radix users must add the `-b radix` flag themselves exactly as the prerequisite note shows. The setup also states that pnpm is required, offers `npm i -g pnpm` as the fix, and then notes that npx and `npm run dev` work the same way, without spelling out an equivalent npx form of the scaffold flag. The claim about the whole trip from create-next-app to a green `next build` taking about 30 seconds on a clean machine belongs to the project, not to anything measured here.

Memory, URL, zustand, or a remote API manifest

Filter state is where these blocks split, and the choice is explicit rather than implicit. The core block ships a memory adapter, which is all a client-side table needs. Teams that want filters in the address bar add `@data-table-filters/data-table-nuqs`, a nuqs URL state adapter, so a filtered view becomes a shareable link and the browser back button walks filter history.

Codebases already running zustand pick `@data-table-filters/data-table-zustand` instead of nuqs. `@data-table-filters/data-table-query` wires a React Query infinite query for server-driven rows, and `@data-table-filters/data-table-remote` drops the app coupling entirely by rendering from an API endpoint's manifest, which suits a table embedded somewhere other than the service that owns the data.

Combining them is undefined territory. The README gives no guidance on pairing the nuqs adapter with the React Query block, and no compatibility statement covers zustand versions, so a project with both a URL-driven page and an infinite feed has to decide which adapter owns the query string.

Twelve cell renderers, a timeline chart, two agent blocks

`@data-table-filters/data-table-cell` carries 12 renderers in one package: text, code, number, bar, heatmap, gauge, badge, boolean, star, status-code, level-indicator and timestamp. That list reads as observability tooling rather than a generic grid, and it explains the rest of the catalogue. `@data-table-filters/data-table-chart` stacks timeline buckets per level and lets you drag to zoom the time filter, so the chart edits the same state the table reads. `@data-table-filters/data-table-actions` renders row and bulk actions from server metadata instead of hardcoded callbacks in the client, and `@data-table-filters/data-table-sheet` opens a row detail side panel.

Two blocks serve agents rather than people. `@data-table-filters/data-table-filter-command-ai` turns natural language into filter inference, and `@data-table-filters/data-table-mcp` exposes an MCP server endpoint for AI agents. Neither carries configuration detail in the README. No model name, environment variable, endpoint path, cost note or failure behaviour is given for the AI filter block, and the MCP entry is one table row with no handshake example, so both need decisions before they run. Agent install paths are documented more fully, through a Claude Code plugin marketplace and through the skills CLI, and the repository carries .claude-plugin/, .mcp.json, skills/ and skills-lock.json to support them.

Why you would wire TanStack Table yourself

The real alternative is the primitives underneath. Repository topics list tanstack-table and tanstack-react-query, and those are the libraries a team reaches for by default: add them as dependencies, describe columns in TypeScript, write the SQL yourself. Ownership differs first. TanStack Table stays a dependency at a version your lockfile pins, while every data-table-filters block lands in your repository as source you maintain, patch and eventually delete. Query surface differs second. Hand-written Drizzle code exposes exactly the filters you implement, whereas the generated route handler here exposes whatever your schema declares, which starts faster and trims slower.

Runtime behaviour differs a third time, in both directions. With SQL filtering, faceted counts travel from Postgres on every request, which keeps large tables fast to page through and adds network cost per facet. A memory adapter avoids both and gives up server-scale tables immediately.

Take the registry path when the team already runs Next.js with shadcn/ui, wants counts and cursor pagination in SQL, and accepts owning the copy it receives. Take the hand-rolled path when pinned versions, a non-Next framework, or filter logic outside a declarative schema matter more than the generated route handler.

Editorial conclusion

data-table-filters fits a team that already ships Next.js with shadcn/ui and wants faceted filters, counts and cursor pagination running in Postgres instead of in the browser. Pass on it if you need a pinned npm dependency, a non-Next framework, or a filter set that does not fit a declarative schema, because each block arrives as source you own and maintain. Before adopting, check that the Radix or Base UI variant typechecks in your app and that you are ready to own 12 cell renderers and 4 filter types the README never names.

Frequently asked questions

How do I install data-table-filters into an existing shadcn app?

Run `npx shadcn@latest add @data-table-filters/data-table @data-table-filters/data-table-schema`, which copies the core block and the schema system into your project as source. Three setups are supported: the CLI default, Base UI (`npx shadcn@latest init -d`) and Radix (`npx shadcn@latest init -b radix -p lyra`).

Can data-table-filters work without a database?

Yes. `DataTableAuto` infers columns, filters and cell renderers from any array of objects, and the core block includes a memory adapter. When rows live in Postgres, filtering, faceted counts and cursor pagination run in SQL through `@data-table-filters/data-table-drizzle`.

What does the data-table-filters schema definition drive?

One `createTableSchema` definition feeds the columns, the filter controls, the row detail sheet, the Drizzle route handler and the MCP tool schema.

Which cell renderers and filter types ship with data-table-filters?

The core block bundles the table engine, a store, 4 filter types and a memory adapter. The cell block adds 12 renderers: text, code, number, bar, heatmap, gauge, badge, boolean, star, status-code, level-indicator and timestamp.

Can an AI agent install data-table-filters?

Yes. Claude Code users add the marketplace `openstatushq/data-table-filters` and install `data-table-filters@openstatus`, while agents supporting the skills CLI can run `npx skills add https://github.com/openstatushq/data-table-filters --skill data-table-filters`. The skill detects the stack, installs the right blocks and generates a schema.

Official sources

  1. Issues
  2. License: MIT
  3. openstatusHQ/data-table-filters on GitHub
  4. Project website
  5. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/openstatushq-data-table-filters.svg)](https://hysenlabs.com/projects/openstatushq-data-table-filters)

Was this useful?