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 →
SvelteDocumentationGuidesResponsive layouts

Responsive layouts

A responsive grid switches column count and layout as the container width crosses breakpoints. The headless engine is createResponsiveLayout: give it a map of per-breakpoint layouts and the measured width, and it resolves the active breakpoint’s cols and layout plus an onLayoutChange that writes back to the right breakpoint. Feed those into createGridContainer.

<!-- ResponsiveBoard.svelte --> <script lang="ts"> import { DragDropProvider } from "@dnd-kit/svelte"; import { type ResponsiveLayouts, createContainerWidth, createResponsiveLayout, } from "@snapgridjs/svelte"; import Grid from "./Grid.svelte"; const width = createContainerWidth(); let layouts = $state<ResponsiveLayouts>({ lg: [ { 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 }, ], }); // Resolve the active breakpoint's column count + layout from the width. Options are // passed as a getter so the result tracks the live width and layouts. const responsive = createResponsiveLayout(() => ({ width: width.width, layouts, onLayoutChange: (_active, all) => (layouts = all), onBreakpointChange: (bp, cols) => console.log("now at", bp, cols), })); </script> <div {@attach width.attach}> <DragDropProvider> <Grid layout={responsive.layout} width={width.width} cols={responsive.cols} onLayoutChange={responsive.onLayoutChange} /> </DragDropProvider> </div>
<!-- Grid.svelte — the column count tracks the active breakpoint, so the grid reflows with it. --> <script lang="ts"> import { type Layout, createGridContainer } from "@snapgridjs/svelte"; import Tile from "./Tile.svelte"; let { layout, width, cols, onLayoutChange, }: { layout: Layout; width: number; cols: number; onLayoutChange: (next: Layout) => void; } = $props(); const container = createGridContainer(() => ({ layout, width, onLayoutChange, gridConfig: { cols } })); </script> <div {@attach container.attach} style={container.style}> {#each layout as it (it.i)} <Tile id={it.i} group={container.group} /> {/each} </div>

Missing breakpoints are generated from the nearest provided one.

Responsive
drag the right edge — columns change at breakpoints

Breakpoints & columns

Defaults mirror react-grid-layout:

BreakpointMin width (px)Columns
lg120012
md99610
sm7686
xs4804
xxs02

Override either with the breakpoints and cols options (exported as DEFAULT_BREAKPOINTS and DEFAULT_BREAKPOINT_COLS if you want to extend them):

const responsive = createResponsiveLayout(() => ({ width: width.width, layouts, breakpoints: { lg: 1280, md: 900, sm: 0 }, cols: { lg: 16, md: 8, sm: 4 }, onLayoutChange: (_active, all) => (layouts = all), }));

onLayoutChange gives you both

The factory’s onLayoutChange option is (activeLayout, allLayouts): the layout for the current breakpoint and the full updated map. Store the map so edits at one breakpoint don’t clobber the others:

onLayoutChange: (_active, all) => (layouts = all),

The onLayoutChange the factory returns (which you pass to createGridContainer) takes care of routing each committed change into the active breakpoint’s entry before calling your option above.

Prefer the turnkey component? <ResponsiveGridLayout> is the component that wraps this factory — pass it layouts, width, and an item snippet and it handles the provider and the grid. See Components for its full prop table.

Last updated on