Server-side rendering
snapgrid works under SSR and static generation. This very site is a statically-exported Next.js app that renders the library. A couple of notes keep it smooth.
Width measurement is SSR-safe
useContainerWidth measures with a ResizeObserver, which only exists in the browser. The hook is
SSR-safe by design:
- it renders at
initialWidth(default1280) on the server and on the first client render, so the markup matches and there’s no hydration mismatch; - it then measures the real width after mount and updates.
const { width, mounted, containerRef } = useContainerWidth({ initialWidth: 1024 });Pick an initialWidth close to your typical container to minimize the first-paint reflow, or gate
on mounted if you’d rather not render until measured.
Avoiding layout flash
Because the server renders at initialWidth, tiles briefly appear at that width before the client
measures. To avoid any flash you can render the grid only once measured:
const { width, mounted, containerRef } = useContainerWidth();
<div ref={containerRef}>
{mounted ? <Board width={width} /> : <div style={{ minHeight: 240 }} />}
</div>;
// Board is your headless grid: a DragDropProvider wrapping useGridContainer.Next.js App Router
In the App Router, the file that renders snapgrid (or any of its hooks) must be a client component.
Add "use client" at the top. dnd-kit attaches sensors in effects, so the interaction is inherently
client-side.
"use client";
import { DragDropProvider } from "@dnd-kit/react";
import { useContainerWidth, useGridContainer } from "@snapgridjs/react";
// …Dragging is purely client-side: there’s no active drag during SSR, so a tile renders in its normal in-grid position on the server and only floats itself once a drag begins in the browser. Nothing to guard.