Skip to content

viktorius007/gridstack.svelte

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

gridstack.svelte

A lightweight, modern Svelte 5 wrapper for GridStack.js v12 - create draggable, resizable dashboard layouts with ease.

πŸ“– Overview

This library provides thin, performant Svelte 5 components that wrap GridStack.js v12, enabling you to build interactive dashboards with drag-and-drop functionality, responsive grids, and dynamic layouts. Built with Svelte's latest runes and snippets syntax for optimal performance.

✨ Features

  • 🎯 Svelte 5 Native - Built with modern runes ($state, $props, $bindable) and snippets
  • πŸš€ Lightweight Wrapper - Minimal abstraction over GridStack.js for maximum performance
  • πŸ“¦ TypeScript Support - Full TypeScript definitions included
  • 🎨 Customizable - Complete access to GridStack.js options and methods
  • πŸ“± Responsive - Mobile-friendly with touch support
  • πŸ”§ Simple API - Easy to use with declarative Svelte components

⚑️ Quick Start

Installation

npm install gridstack.svelte
# or
pnpm add gridstack.svelte

Basic Usage

<script lang="ts">
	import Grid, { GridItem } from 'gridstack.svelte';
	import 'gridstack/dist/gridstack.min.css';
</script>

<Grid>
	<GridItem x={0} y={0} w={4} h={2}>Widget 1</GridItem>
	<GridItem x={4} y={0} w={4} h={4}>Widget 2</GridItem>
	<GridItem x={8} y={0} w={2} h={2}>Widget 3</GridItem>
</Grid>

Advanced Example

<script lang="ts">
	import Grid, { GridItem } from 'gridstack.svelte';
	import { GridStack } from 'gridstack';
	import 'gridstack/dist/gridstack.min.css';

	let grid = $state.snapshot(null);
	let options = $state({
		margin: 8,
		cellHeight: 70,
		acceptWidgets: true,
		removable: '#trash'
	});

	$effect(() => {
		// Setup drag-in from external elements
		GridStack.setupDragIn('.newWidget', undefined, [{ w: 2, h: 2, content: 'New Item' }]);
	});
</script>

<Grid ref={grid} {options}>
	<GridItem id="w1" x={0} y={0} w={4} h={2}>Dashboard Widget</GridItem>

	<GridItem id="w2" x={4} y={0} w={4} h={4} noResize={true} locked={true}>
		Locked Widget (Can't resize or move)
	</GridItem>

	<GridItem id="w3" x={8} y={0} w={2} h={2} noMove={true}>Can resize but not move</GridItem>
</Grid>

πŸ“š API

Grid Component

The main container component that initializes GridStack.

Props:

  • ref - Bindable reference to the GridStack instance
  • options - GridStack configuration options (margin, cellHeight, etc.)
  • children - Snippet containing GridItem components

GridItem Component

Individual grid items that can be dragged and resized.

Props:

  • id - Unique identifier for the item
  • x, y - Grid position (0-based)
  • w, h - Width and height in grid units
  • minW, maxW - Min/max width constraints
  • minH, maxH - Min/max height constraints
  • noResize - Disable resizing
  • noMove - Disable moving
  • locked - Lock item (no resize, move, or drag)
  • autoPosition - Auto-position item if x/y not provided
  • children - Content to display inside the grid item

🎨 Styling Guide - Understanding GridStack's Structure

GridStack's Layer Structure

1. .grid-stack - The Container

  • Purpose: The overall grid container that manages the layout system
  • What it does: Sets up the coordinate system, handles grid calculations
  • Don't touch: Let GridStack manage this completely

2. .grid-stack-item - The Positioned Wrapper

  • Purpose: The absolutely positioned element that GridStack moves around
  • What it does:
    • Handles positioning (top, left, width, height)
    • Uses CSS variables for grid calculations (--gs-column-width, --gs-cell-height)
    • Contains resize handles as direct children
    • Manages all animations and transitions during drag/resize
  • Don't touch: Position, dimensions, padding, transforms, transitions
  • Never add: Any CSS that affects positioning or animation

3. .grid-stack-item-content - The Margin/Gap Manager

  • Purpose: Creates the visual gaps between widgets
  • What it does:
    • Uses position: absolute with top, right, bottom, left
    • These positions reference CSS variables (--gs-item-margin-*) to create gaps
    • Acts as a "negative space" creator
  • NEVER style this: Any styling breaks GridStack's margin system
  • Don't add: height: 100%, display: flex, backgrounds, borders, etc.

4. Your content - Direct child of .grid-stack-item-content

  • Purpose: Your actual widget content
  • What goes here: ALL your visual styling
    • Backgrounds, borders, shadows
    • Padding for internal spacing
    • Layout properties (flex, grid)
    • height: 100% to fill the available space
  • Best practice: Use a single wrapper div as the immediate child

The Critical Lesson

GridStack uses a "negative space" approach for margins:

  • The .grid-stack-item is the full cell size
  • The .grid-stack-item-content is positioned inside with offsets
  • The gap between items is created by these offsets, not by margins

This is why styling .grid-stack-item-content breaks everything - you're interfering with the positioning layer that creates the gaps.

Correct Structure

<div class="grid-stack">                     <!-- GridStack manages -->
  <div class="grid-stack-item">              <!-- GridStack positions -->
    <div class="grid-stack-item-content">    <!-- GridStack gaps - DON'T TOUCH -->
      <div class="your-widget">               <!-- YOUR styling goes here -->
        <!-- Your content -->
      </div>
    </div>
  </div>
</div>

The mistake we made was trying to "help" GridStack by styling its internal structure, when we should have just styled our own content and let GridStack handle its layout mechanics.

πŸ› οΈ Development

# Install dependencies
pnpm install

# Run development server
pnpm dev

# Build library
pnpm build

# Run tests
pnpm test

# Type checking
pnpm check

πŸ“„ License

MIT

🀝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

πŸ”— Links

About

Svelte 5 wrapper for GridStack.js

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •