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

Cross-grid dragging

Put two or more grids on one dnd-kit provider and tiles can be dragged between them. The source grid loses the tile; the destination gains it. Each grid keeps its own controlled layout. <SnapGridGroup> is that shared provider — it’s just dnd-kit’s DragDropProvider, named for intent — so each grid hosts itself with useGridContainer, and a dragged tile floats itself across the seam (no overlay to wire).

Cross-grid is the managed, grid-to-grid case. To drag between a grid and a non-grid dnd-kit sortable (a list, a kanban column), see dnd-kit interop.

import { SnapGridGroup, useGridContainer, useGridItem } from "@snapgridjs/react"; function Grid({ layout, width, onLayoutChange }) { // Each grid hosts itself and returns its own `group`; the shared provider // comes from the enclosing SnapGridGroup. const { containerProps, group } = useGridContainer({ layout, width, onLayoutChange, gridConfig: cfg }); return ( <div {...containerProps}> {layout.map((it) => ( <Tile key={it.i} id={it.i} group={group} /> ))} </div> ); } function Tile({ id, group }) { const { ref, style } = useGridItem({ id, group }); return ( <div ref={ref} style={style} className="tile"> {id} </div> ); } <SnapGridGroup> <Grid layout={left} width={w} onLayoutChange={setLeft} /> <Grid layout={right} width={w} onLayoutChange={setRight} /> </SnapGridGroup>;
Cross-grid dragging
drag a tile between the two grids

How it works

Cross-grid dragging is just two grids on one dnd-kit DragDropProvider. <SnapGridGroup> supplies that shared provider; a drag that starts in one grid is received by whichever grid dnd-kit’s collision system resolves under the pointer. On drop:

  • the source grid removes the tile and fires its onLayoutChange with the tile gone;
  • the destination grid inserts the tile at the drop cell and fires its onLayoutChange with the tile added.

Both updates happen in the same gesture, each against its own layout state.

Item ids must be unique across every grid in a group. They share one drag manager. If two grids can hold an item with the same i, a cross-grid drop can’t tell them apart.

<SnapGridGroup> is exactly dnd-kit’s <DragDropProvider> — use whichever you like; grids under one provider exchange tiles either way. Prefer the turnkey shell? Swap each <Grid> for a <GridLayout> with keyed children inside the same group; it bundles the container and items for you.

No overlay to wire. A dragged tile floats itself — it lifts into the top layer and crosses the gap between grids unclipped, carrying its own content with it. So the preview always shows the right tile, from whichever grid it came, with nothing extra to render.

Callbacks

The destination grid signals a received tile through onLayoutChange only. It does not fire onDragStop, because it never fired onDragStart (the source grid owns the drag’s start/stop pair). Wire cross-grid persistence to onLayoutChange on both grids.

Dropping outside any grid

If a tile is dropped outside every grid in the group, the move reverts. The source keeps it and no onLayoutChange fires.

Want a grid inside a tile of another rather than side-by-side siblings? See Nested grids — they also cross levels by default, and you can give a sub-grid its own provider to keep it self-contained.

Last updated on