Skip to content
dnd-grid

Compactors

Control how layouts pack and collide.

Compactors are pluggable strategies that determine how items pack when space opens up and how collisions are resolved. Pass a Compactor to the compactor prop on DndGrid, or use them with responsive layouts.

Built-in compactors

CompactorBehavior
verticalCompactorDefault. Packs items upward by row.
horizontalCompactorPacks items left-to-right, wrapping to the next row.
noCompactorLeaves items where they are, no packing.
verticalOverlapCompactorVertical mode but allows overlap.
horizontalOverlapCompactorHorizontal mode but allows overlap.
fastVerticalCompactorFaster vertical packing for large layouts.
fastHorizontalCompactorFaster horizontal packing for large layouts.
fastVerticalOverlapCompactorFast vertical mode with overlap allowed.
fastHorizontalOverlapCompactorFast horizontal mode with overlap allowed.
import {
  verticalCompactor,
  horizontalCompactor,
  noCompactor,
  fastVerticalCompactor,
} from "@dnd-grid/react";

<DndGrid compactor={verticalCompactor} />
<DndGrid compactor={horizontalCompactor} />
<DndGrid compactor={noCompactor} />
<DndGrid compactor={fastVerticalCompactor} />

Overlap and collision behavior

  • allowOverlap: true skips collision resolution. Items can overlap freely.
  • preventCollision: true blocks a move if it would collide with another item.
import { verticalCompactor, verticalOverlapCompactor } from "@dnd-grid/react";

<DndGrid compactor={{ ...verticalCompactor, preventCollision: true }} />
<DndGrid compactor={verticalOverlapCompactor} />

Helpers and custom compactors

A compactor has four fields: type, allowOverlap, compact, and onMove. You can implement your own, or build on the helpers below:

  • compactItemVertical
  • compactItemHorizontal
  • resolveCompactionCollision
import { type Compactor, compactItemVertical } from "@dnd-grid/react";

const myCompactor: Compactor = {
  type: "vertical",
  allowOverlap: false,
  compact(layout, _cols) {
    // Reorder items by your own logic, then compact vertically.
    const sorted = [...layout];
    const out = sorted.map((item) => ({ ...item }));
    const compareWith = out.filter((item) => item.static);
    let maxY = 0;

    for (const item of out) {
      if (!item.static) {
        compactItemVertical(compareWith, item, out, maxY);
        maxY = Math.max(maxY, item.y + item.h);
        compareWith.push(item);
      }
    }

    return out;
  },
  onMove(layout, item, x, y) {
    return layout.map((entry) =>
      entry.id === item.id ? { ...entry, x, y, moved: true } : entry,
    );
  },
};