I built a 100% Declarative, Schema-Driven Table Engine for Next.js (Zod + TanStack + nuqs).

Show /r/reactjs

Reddit Body Text:

Hey everyone,

I got tired of the endless boilerplate when building admin dashboards. Every table needed the same things: URL sync, filtering, sorting, and bulk actions. So I built a "table engine" that is entirely driven by your Zod schema.

The "Magic": The engine uses your schema to automatically parse filter types (Numbers, Dates, Booleans) from the URL and validates them.

Heres a small video demo, what you can get:

https://youtu.be/g609MF9fY2o

1. The Schema (Source of Truth)

TypeScript

export const userSchema = z.object({
  id: z.number(),
  name: z.string(),
  is_admin: z.boolean(),
  created_at: z.string(), 
});

2. Custom Filters (The Killer Feature)

This is where it gets powerful. You can attach any UI component (DatePickers, Selects, etc.) directly to your column definition. The engine handles the state; you just provide the UI:

TypeScript

{
  accessorKey: "is_admin",
  header: "Status",
  meta: {
    filterLabel: "Filter by Status",
    FilterComponent: ({ value, onChange, label }) => (
      <Select value={value || "all"} onValueChange={(val) => onChange(val === "all" ? "" : val)}>
        <SelectTrigger><SelectValue placeholder={label} /></SelectTrigger>
        <SelectContent>
          <SelectItem value="all">All Users</SelectItem>
          <SelectItem value="true">Admins Only</SelectItem>
          <SelectItem value="false">Regular Users</SelectItem>
        </SelectContent>
      </Select>
    ),
  },
}

3. Implementation

The page component stays clean. No state management, no useEffect for URL sync:

TypeScript

<DataTable
  schema={userSchema}
  data={users}
  columns={columns}
  bulkActions={bulkActions}
  enableRowOrdering={true}
  labels={{
    pagination: { rowsPerPage: "Zeilen pro Seite" },
    table: { noData: "Keine Daten gefunden" }
  }}
/>

Key Features:

  • 🔗 Full URL Sync: Deep-linking for everything. Refresh the page? All filters, sorting, and pagination stay exactly as they were.
  • 🛡️ Type-Safe Filters: If your Zod schema says it's a number, the filter parses it as a number.
  • 🚜 Advanced Bulk Actions: Define async actions with dynamic confirmation messages like "Delete {count} users?".
  • ⚡ Performance: Virtual scrolling (@tanstack/react-virtual) for thousands of rows.
  • 🖱️ Drag & Drop: Column and row reordering built-in.
  • 🌍 Localized: Every label is customizable via the labels prop for easy i18n.

Current State & Documentation:

  • The repo is live, but honestly, the documentation is still lacking and a bit of a mess. I’m planning to clean it up and provide proper integration guides over the next few days. I also have a day job, so please bear with me!

Upcoming Features:

  • Row Ordering Callback: Currently, row reordering is visual-only. I’ll be adding the onRowOrderChange callback very soon so you can actually sync the new order back to your API/Database.

Shadcn-Style (Copy & Paste)

I decided against an NPM package. It’s a set of components and hooks you copy into your project. You own the code, you can tweak the UI, but the heavy lifting is handled by the engine.

Used libraries:

zod @tanstack/react-table @tanstack/react-virtual @tanstack/react-pacer nuqs @dnd-kit/core @dnd-kit/sortable @dnd-kit/utilities lucide-react

Used shadcn components:

button input label select table tabs dropdown-menu switch skeleton checkbox badge card alert-dialog popover separator

Please note that im not a professional dev at all and there may be mistakes. Im neither a trained dev nor studied one. Im doing this mainly because its kinda fun in my freetime and are more a dev ops engineer than a real full-stack dev.

Heres the repo for everyone who is interested in this.
https://github.com/Zaryu/next-schema-table

For transparency: the documentation is also somewhat half generated with claude, as i only really bothered and wanted a table for my current project thats more or less standardized and to be used with different data sets.

I’m looking for feedback! What’s your biggest pain point with tables in Next.js right now?

Posted Jan 11, 2026, 8:08 PM UTC

69
Loading comments…