Next.js data grid
A data grid for Next.js and the App Router
Fetch the rows in a Server Component, render the grid in a Client Component, and ship it. The grid renders its column headers and skeleton on the server, sorts and filters large data in a Web Worker it starts itself, and needs no extra build configuration.
Everything on this page is in the free Community edition (@kanunilabs/datagrid-react).
One client boundary
The grid holds state, so the file that renders it starts with "use client". Fetch the rows in a Server Component and pass them down as a prop; only the grid itself is client code.
No worker file to copy
Above roughly 20,000 rows the grid moves filtering and sorting into a Web Worker. The worker is compiled into the package and started from a Blob URL, so Next never has to resolve a worker file from node_modules, and nothing goes into public/.
Server-rendered markup
The server render outputs the grid frame and the column headers, so the page is not an empty box before hydration; rows arrive with the client.
App Router: server data, client grid
// app/sales/SalesGrid.tsx
'use client';
import { DataGrid, type ReactGridColumnDef } from '@kanunilabs/datagrid-react';
import '@kanunilabs/datagrid-react/styles.css';
type Sale = { id: number; product: string; revenue: number };
const columns: ReactGridColumnDef<Sale>[] = [
{ field: 'product', headerName: 'Product', width: 220 },
{ field: 'revenue', headerName: 'Revenue', dataType: 'number', width: 140 },
];
export function SalesGrid({ rows }: { rows: Sale[] }) {
return <DataGrid gridId="sales" dataSource={rows} rowKey="id" columns={columns} style={{ height: 500 }} />;
}
// app/sales/page.tsx (a Server Component)
import { SalesGrid } from './SalesGrid';
export default async function SalesPage() {
const rows = await getSales(); // your data access
return <SalesGrid rows={rows} />;
}Every option: SSR and bundlers guide.
Questions
- Do I need dynamic(() => import(...), { ssr: false })?
- Not for the DataGrid: it renders on the server as markup and becomes interactive on the client. Mark the file that renders it with "use client".
- Can the rows come from an API instead?
- Yes, and that is free too: with a server-side data source the grid asks your endpoint for the rows in view as the user scrolls, and filtering, sorting and totals run on your server.
- What about the pivot table?
- The PivotGrid has its own Next.js page: it is loaded client-side only, and the worker needs no setup either.