Skip to Content
snapgrid is a react-grid-layout v2 alternative built on dnd-kit. Drag, resize, repack, and drag between grids.
DocumentationGetting Started

Getting Started

snapgrid is a react-grid-layout  v2 alternative built on dnd-kit . It gives you draggable, resizable, responsive grid layouts, plus things RGL can’t do, like dragging tiles between grids and swapping the packing algorithm at runtime.

It’s controlled (you own the layout array) and headless-first (it ships behaviour, not markup), with a thin drop-in component layer for the common case.

Drag & resize
drag a tile · resize from the corner

Install

snapgrid is split into three packages. Most apps only need @snapgridjs/react, which pulls in @snapgridjs/core. Add the dnd-kit peers alongside it.

pnpm add @snapgridjs/react @dnd-kit/react @dnd-kit/dom

@snapgridjs/extras adds optional packing algorithms (masonry, gravity, shelf). Install it only if you need them: pnpm add @snapgridjs/extras.

Your first grid

Hold the layout in state

A layout is an array of items, each with an id (i), a position (x, y), and a size (w, h) in grid units. snapgrid never mutates it. You keep it in state and apply every change yourself.

import { useState } from "react"; import type { Layout } from "@snapgridjs/react"; const [layout, setLayout] = useState<Layout>([ { i: "a", x: 0, y: 0, w: 4, h: 2 }, { i: "b", x: 4, y: 0, w: 4, h: 2 }, { i: "c", x: 8, y: 0, w: 4, h: 2 }, ]);

Measure the container width

The grid needs a pixel width to map columns to positions. useContainerWidth measures it with a ResizeObserver. Attach its containerRef to the element whose width should drive the grid.

import { useContainerWidth } from "@snapgridjs/react"; const { width, containerRef } = useContainerWidth();

Render <GridLayout> with keyed children

Each child is keyed by its item’s i. snapgrid positions it; you render whatever’s inside.

import { GridLayout } from "@snapgridjs/react"; <div ref={containerRef}> <GridLayout layout={layout} width={width} onLayoutChange={setLayout}> {layout.map((item) => ( <div key={item.i} className="tile"> {item.i} </div> ))} </GridLayout> </div>;

Drag and resize

That’s it: tiles drag, the rest compact upward, and a resize handle sits in the bottom-right corner by default. Every committed change flows back through onLayoutChange.

Putting it together

Board.tsx
import { GridLayout, useContainerWidth, type Layout } from "@snapgridjs/react"; import { useState } from "react"; export function Board() { const { width, containerRef } = useContainerWidth(); const [layout, setLayout] = useState<Layout>([ { i: "a", x: 0, y: 0, w: 4, h: 2 }, { i: "b", x: 4, y: 0, w: 4, h: 2 }, { i: "c", x: 8, y: 0, w: 4, h: 3 }, { i: "d", x: 0, y: 2, w: 6, h: 2 }, ]); return ( <div ref={containerRef}> <GridLayout layout={layout} width={width} onLayoutChange={setLayout} gridConfig={{ cols: 12, rowHeight: 60, margin: [12, 12] }} resizeConfig={{ handles: ["se", "e", "s"] }} > {layout.map((item) => ( <div key={item.i} className="tile"> {item.i} </div> ))} </GridLayout> </div> ); }

snapgrid ships no CSS of its own. The tiles above are styled by your own .tile class. See Styling for the classes and data attributes snapgrid exposes.

Where to next

Last updated on