Skip to Content
snapgrid is a react-grid-layout v2 alternative built on dnd-kit. Drag, resize, repack, and drag between grids.
RoadmapNext: Vue, Svelte, Solid & vanilla-TS bindings on snapgrid's framework-agnostic core.See the roadmap →

a dnd-kit grid · react-grid-layout alternative

Grids that drag, resize, and repack.

A headless-first grid layout built on dnd-kit — draggable, resizable, repacking tiles that compose with the sortables and droppables you already have. A component layer makes react-grid-layout users feel right at home too.

38 kB brotlisnapgrid ~8 kB + dnd-kit ~30 kB

Why snapgrid

A 30-second example

Headless
import { DragDropProvider } from "@dnd-kit/react";
import { useContainerWidth, useGridContainer, useGridItem } from "@snapgridjs/react";
import { useState } from "react";

function Board() {
  const { width, containerRef } = useContainerWidth();
  const [layout, setLayout] = useState([
    { 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 },
  ]);

  // DragDropProvider is the outermost element; the grid host (Surface) sits
  // inside it, so useGridContainer resolves the provider's dnd-kit manager. A
  // dragged tile floats itself, so there's no overlay to render.
  return (
    <div ref={containerRef}>
      <DragDropProvider>
        <Surface layout={layout} width={width} onLayoutChange={setLayout} />
      </DragDropProvider>
    </div>
  );
}

function Surface({ layout, width, onLayoutChange }) {
  // useGridContainer is the grid host; it returns the grid's `group`.
  const { containerProps, group } = useGridContainer({ layout, width, onLayoutChange });
  return (
    <div {...containerProps}>
      {layout.map((it) => <Tile key={it.i} id={it.i} group={group} />)}
    </div>
  );
}

function Tile({ id, group }) {
  // each tile resolves its grid by `group` — like a dnd-kit sortable
  const { ref, style } = useGridItem({ id, group });
  return <div ref={ref} style={style} className="tile">{id}</div>;
}

Coming from react-grid-layout?

The <GridLayout> component layer mirrors react-grid-layout v2's model — same controlled layout, onLayoutChange, and config objects — so RGL users adopt it quickly, then drop any grid down to the headless hooks at their own pace. Same engine, no second migration.

react-grid-layout v2 → snapgrid
import ReactGridLayout, { useContainerWidth, verticalCompactor } from "react-grid-layout";
import "react-grid-layout/css/styles.css";
import { GridLayout, useContainerWidth, verticalCompactor } from "@snapgridjs/react";

function Board() {
  const { width, containerRef, mounted } = useContainerWidth();

  return (
    <div ref={containerRef}>
      {mounted && (
        <ReactGridLayout
        <GridLayout
          width={width}
          layout={layout}
          gridConfig={{ cols: 12, rowHeight: 30 }}
          dragConfig={{ enabled: true, handle: ".handle" }}
          compactor={verticalCompactor}
        >
          {children}
        </ReactGridLayout>
        </GridLayout>
      )}
    </div>
  );
}

Migration path

  • Not a literal drop-in. Same API shape, but you restyle — snapgrid ships no CSS and uses its own class names.
  • v2 hooks aren't mirrored. useGridLayout / useResponsiveLayout code moves to the headless API.
  • On v1? No one-import shim — its WidthProvider / flat-prop API is dated enough that it's worth modernising. The migration guide maps it prop by prop.
Full comparison & migration guide →