Documentation

SSR & bundlers

The grid renders on the server and hydrates normally. Nothing touches window, document or ResizeObserver outside an effect, so a page containing a grid does not need ssr: false or a typeof window guard.

This is covered by tests that render the component to a string in a DOM-free environment — including with the toolbar, filter row, group panel, pager, summary bar and a remote data source all switched on.

What the server renders

On the serverAfter hydration
Root, header, ARIA rolesrenderedunchanged
Column captionsrenderedunchanged
Row windowemptymeasured and filled
Web Workernever constructedconstructed above the threshold
Remote DataSourceload() called once, not awaitedloaded by the client

The row window is empty because the viewport has no size until the browser measures it. Guessing a row count server-side would render rows the client immediately replaces.

On a remote source the server render calls load() once and does not wait for it — the markup goes out without rows and the client loads its own after hydration. With an absolute URL that is one extra request per page render whose answer is discarded; a relative fetch('/api/...') simply fails on the server, and the grid absorbs the failure without breaking the render.

The markup still contains the grid skeleton and the column headers, so the pre-hydration page is not a blank box.

Next.js (App Router)

The grid is a client component — it holds state and subscribes to events. Mark the file that renders it:

'use client';

import { DataGrid } from '@kanunilabs/datagrid-react';
import '@kanunilabs/datagrid-react/styles.css';

export function SalesGrid({ rows }) {
  return <DataGrid gridId="sales" dataSource={rows} rowKey="id" columns={columns} />;
}

A server component can fetch the rows and pass them down as a prop; only the grid itself needs the client boundary.

Import the stylesheet once — in the root layout or in the client component.

The worker in Next.js

Nothing to do. The worker is compiled into the package and starts from a Blob URL, so Next never has to resolve a worker file out of a dependency — which it does not do.

Two cases still need the file, and it ships in the package for them:

  • a Content-Security-Policy without worker-src … blob: — the browser refuses the Blob, and only a real URL will start the worker;
  • wanting the worker as its own cacheable file rather than inlined in your bundle.

Either way, serve the file from your own origin: a browser will not start a worker script from another domain, so a CDN on a different host does not work.

cp node_modules/@kanunilabs/datagrid-core/dist/datagrid.worker.js public/
<DataGrid worker={{ url: '/datagrid.worker.js' }} /* ... */ />

If the worker cannot start for any reason the grid still works: it runs the same pipeline on the main thread and warns once in development. The only difference is that a large sort blocks the UI instead of running off-thread.

Vite

Also nothing to do. If you need the file route (CSP or CDN, as above):

import workerUrl from '@kanunilabs/datagrid-core/dist/datagrid.worker.js?url';

<DataGrid worker={{ url: workerUrl }} /* ... */ />

Other bundlers

Any setup that can serve a static .js file works: copy node_modules/@kanunilabs/datagrid-core/dist/datagrid.worker.js somewhere public and pass its URL. The file is self-contained — it has no imports of its own, so no additional chunk resolution is involved.

Turning the worker off

<DataGrid worker={{ enabled: false }} />     {/* always main thread */}
<DataGrid worker={{ threshold: 50_000 }} />  {/* offload later than the default 20.000 */}

Below the threshold the main thread is genuinely faster — the round trip costs more than the sort saves — so small grids never use the worker regardless.

Content Security Policy

The default worker starts from a Blob URL, so a policy that restricts workers needs worker-src 'self' blob:. If you serve the file yourself instead (see above), it is loaded from your own origin and worker-src 'self' is enough. The grid does not use eval, inline scripts or remote resources.

Next: performance.