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, and two-way dnd-kit interop with Droppables & Sortables.See the roadmap →

react-grid-layout alternative · dnd-kit powered

Grids that drag, resize, and repack.

A controlled, headless-first grid layout for React: draggable and resizable tiles, pluggable packing, responsive breakpoints, and dragging tiles between grids. Built on dnd-kit.

drag
resize
repack
responsive
cross-grid
33 kB brotlisnapgrid ~6 kB + dnd-kit ~27 kB

Why snapgrid

Coming from react-grid-layout?

snapgrid keeps everything you rely on in RGL — the same controlled layout model, onLayoutChange, responsive breakpoints, resize limits, and static tiles — and adds cross-grid dragging, nested grids, a headless mode, and keyboard-accessible dragging. The real difference is the engine underneath: snapgrid runs on dnd-kit, the de-facto standard for drag-and-drop in React.

  • Already using dnd-kit? snapgrid slots into your existing interaction layer, and adds only its own ~6 kB on top of the dnd-kit you already ship.
  • Accessibility RGL lacks. dnd-kit gives every tile keyboard dragging and screen-reader support out of the box; react-draggable / react-resizable don't.
  • Modern, maintained input. One pointer · touch · keyboard sensor model instead of RGL's older handlers.
Full comparison & migration guide →

A 30-second example

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: 2 },
  ]);

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