@snapgridjs/svelte
v0.10.0
Published
Svelte 5 grid-layout components built on dnd-kit — a react-grid-layout v2 alternative.
Maintainers
Readme
@snapgridjs/svelte
A react-grid-layout v2 alternative, built on dnd-kit — for Svelte 5.
Draggable, resizable, responsive grid layouts for Svelte — with pluggable packing and dragging tiles between grids.
Documentation · Getting Started · Examples · API
The Svelte binding of snapgrid. Same framework-free core + dnd-kit engine as
@snapgridjs/reactand@snapgridjs/vue— a grid behaves identically whichever framework renders it.
Why snapgrid
- Controlled & predictable — you own the layout array; every change comes back through
onLayoutChange. No hidden state. - Headless-first — compose
createGridContainer+ factories under a dnd-kitDragDropProviderfor full control of your markup — or drop in the turnkey<GridLayout>when you don't need that. Ships no CSS. - Svelte 5 native — runes + attachments (
{@attach}); tiles declare agroup, like a dnd-kit sortable. Fine-grained reactivity, nothing to memoize. - Pluggable packing —
vertical/horizontal/none, plusmasonry/gravity/shelffrom@snapgridjs/extras, or your ownCompactor. - Cross-grid dragging — wrap grids in a
<SnapGridGroup>and drag tiles between them. - Nested grids — drop a grid inside a tile of another and drag tiles between levels; isolate a sub-grid with its own provider when you want it contained.
- dnd-kit interop — drag between a grid and a dnd-kit
createSortablelist or board (cards in, tiles out, both reorder) under one provider, viasnapMove. - Responsive — per-breakpoint layouts with
<ResponsiveGridLayout>. - SSR-safe (SvelteKit) and TypeScript-first (types included).
Install
pnpm add @snapgridjs/svelte @dnd-kit/svelte @dnd-kit/domRequires Svelte 5 (svelte@^5.29, a peer dependency). @snapgridjs/extras (masonry/gravity/shelf packers) is optional.
Quick start
snapgrid is headless-first: you compose factories with a dnd-kit DragDropProvider and render your own markup. Because a tile's createGridItem must run inside the provider, the grid host lives in a child component.
<!-- Board.svelte -->
<script lang="ts">
import { DragDropProvider, createContainerWidth } from "@snapgridjs/svelte";
import Surface from "./Surface.svelte";
let layout = $state([
{ 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 },
]);
const width = createContainerWidth();
</script>
<!-- DragDropProvider is the outermost element; Surface runs createGridContainer
inside it, so it resolves the provider's dnd-kit manager. -->
<div {@attach width.attach}>
<DragDropProvider>
<Surface {layout} width={width.width} onLayoutChange={(next) => (layout = next)} />
</DragDropProvider>
</div><!-- Surface.svelte — the grid host; returns the grid's `group`. -->
<script lang="ts">
import { createGridContainer } from "@snapgridjs/svelte";
import Tile from "./Tile.svelte";
let { layout, width, onLayoutChange } = $props();
const container = createGridContainer(() => ({ layout, width, onLayoutChange }));
</script>
<div {@attach container.attach} style={container.style}>
{#each layout as it (it.i)}
<Tile id={it.i} group={container.group} />
{/each}
</div><!-- Tile.svelte — each tile resolves its grid by `group`, like a dnd-kit sortable. -->
<script lang="ts">
import { createGridItem } from "@snapgridjs/svelte";
let { id, group } = $props();
const tile = createGridItem({ id, group });
</script>
<div {@attach tile.attach} style={tile.style} class="tile">{id}</div>Prefer a ready-made component? The turnkey <GridLayout> wraps these same factories (and supplies the provider) — pass an item snippet and you're done:
<GridLayout {layout} {width} onLayoutChange={(next) => (layout = next)}>
{#snippet item(it)}
<div class="tile">{it.i}</div>
{/snippet}
</GridLayout>→ Full walkthrough in Getting Started.
License
MIT © Edmond Leung
