Skip to Content
New — snapgrid now ships for Svelte 5: the same dnd-kit-native, headless-first grid — drag, resize, repack, and drag between grids. See it in Svelte →
SvelteDocumentationGuidesComponent layer

Component layer

snapgrid is headless-first, but you don’t have to wire the factories yourself. The component layer is a thin shell in the react-grid-layout style over those exact factories: <GridLayout> bundles the dnd-kit DragDropProvider, the container, the items, and the placeholder, so you never touch dnd-kit directly.

This is the escape hatch. If the headless provider/host/tile wiring is more than you want, reach for <GridLayout> — it mirrors react-grid-layout v2, so it’s the gentlest on-ramp. When one grid later needs custom markup, drop just that grid down to the factories. Same engine; the two layers mix freely.

<GridLayout>

A controlled grid. Each layout item’s content comes from an item snippet — Svelte has no keyed-children analog, so the snippet receives the item (keyed by i) and snapgrid positions it and renders the resize handles and placeholder for you.

<script lang="ts"> import { GridLayout, createContainerWidth, type Layout } from "@snapgridjs/svelte"; const width = createContainerWidth(); let layout = $state<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 }, ]); </script> <div {@attach width.attach}> <GridLayout {layout} width={width.width} onLayoutChange={(next) => (layout = next)} gridConfig={{ cols: 12, rowHeight: 60, margin: [12, 12] }} resizeConfig={{ handles: ["se", "e", "s"] }} > {#snippet item(it)} <div class="tile">{it.i}</div> {/snippet} </GridLayout> </div>

It supplies its own DragDropProvider; nest several (or wrap them in <SnapGridGroup>) and they share one.

Component layer
the turnkey <GridLayout> — no factories, no dnd-kit wiring

Config props map 1:1 to the factory options

Every behaviour prop on <GridLayout> is the same option you’d pass to createGridContainer — only the spelling differs (a component prop vs. an object key). So each feature guide applies to both layers:

PropWhat it doesGuide
gridConfigColumns, row height, margins, padding, maxRows.Concepts
dragConfigHandle, cancel, threshold, bounds, snap.Dragging
resizeConfigWhich handles to show.Resizing
compactorPacking algorithm.Compaction
dropConfig / onDropAccept external draggables.External drop
isDraggable / isResizable / autoSizeGrid-level toggles.
onDragStartonResizeStopLifecycle callbacks.Events

See Components → GridLayout for the complete prop table.

<ResponsiveGridLayout>

The turnkey wrapper over createResponsiveLayout. Give it a per-breakpoint layouts map instead of a single layout; it switches column count and layout as width crosses breakpoints.

<script lang="ts"> import { ResponsiveGridLayout, createContainerWidth, type ResponsiveLayouts } from "@snapgridjs/svelte"; const width = createContainerWidth(); let layouts = $state<ResponsiveLayouts>({ lg: [/* … */] }); </script> <div {@attach width.attach}> <ResponsiveGridLayout width={width.width} {layouts} onLayoutChange={(_active, all) => (layouts = all)} > {#snippet item(it)} <div class="tile">{it.i}</div> {/snippet} </ResponsiveGridLayout> </div>

Cross-grid with components

Wrap sibling grids in <SnapGridGroup> — the shared provider — and tiles drag between them. (Nested <GridLayout>s share a provider automatically.)

<SnapGridGroup> <GridLayout layout={left} width={w} onLayoutChange={(next) => (left = next)}> {#snippet item(it)} <div class="tile">{it.i}</div> {/snippet} </GridLayout> <GridLayout layout={right} width={w} onLayoutChange={(next) => (right = next)}> {#snippet item(it)} <div class="tile">{it.i}</div> {/snippet} </GridLayout> </SnapGridGroup>

Item ids must be unique across all grids that share a provider — they share one drag manager.

Composing the pieces

The layer isn’t all-or-nothing. <GridItem> and <GridPlaceholder> are the same tiles <GridLayout> renders, exposed so you can drop them into a surface you host with createGridContainer — handy when you want the styled tile but control of the container:

<script lang="ts"> import { createGridContainer, GridItem, GridPlaceholder, type Layout } from "@snapgridjs/svelte"; let { layout, width, onLayoutChange }: { layout: Layout; width: number; onLayoutChange: (next: Layout) => void; } = $props(); const container = createGridContainer(() => ({ layout, width, onLayoutChange })); </script> <div {@attach container.attach} style={container.style}> {#each layout as it (it.i)} <GridItem id={it.i} group={container.group}>{it.i}</GridItem> {/each} <GridPlaceholder group={container.group} /> </div>

<GridItem> applies the stable .snapgrid-item class and data-grid-id / data-dragging attributes (see Styling) and updates only its own slice, so re-rendering the surface doesn’t touch every tile.

There’s no drag overlay to manage at either layer — a dragged tile floats itself. See Components for the full prop tables and Headless usage for the factories.

Last updated on