Documentation
Everything you need to add drag, resize, and reorder to your app.
Installation
npm install gridkit-layoutOr with yarn/pnpm:
yarn add gridkit-layout
pnpm add gridkit-layoutQuick Start
Create a grid, add items, and you're done.
import { GridKit } from 'gridkit-layout'
// Create a grid inside a container element
const grid = GridKit.create('#dashboard', {
collision: true,
animate: true,
bounds: true
})
// Add items
grid.add({
id: 'widget-1',
x: 0,
y: 0,
w: 400,
h: 200,
content: document.getElementById('my-widget')
})
// Listen for changes
grid.on('change', (items) => {
localStorage.setItem('layout', JSON.stringify(items))
})API Reference
GridKit.create(el, options?)
Creates a new GridKit instance. Accepts a selector string or HTMLElement.
const grid = GridKit.create('#container', { collision: true })grid.add(item)
Adds an item to the grid. Returns the created grid item.
grid.add({
id: 'unique-id',
x: 0, y: 0, // position in pixels
w: 300, h: 200, // size in pixels
content: element, // HTMLElement to render
minW: 100, // optional min width
minH: 80, // optional min height
maxW: 600, // optional max width
maxH: 400, // optional max height
draggable: true, // default: true
resizable: true // default: true
})grid.remove(id)
Removes an item by ID.
grid.remove('widget-1')grid.update(id, props)
Updates item properties (position, size, constraints).
grid.update('widget-1', { x: 100, y: 50, w: 500 })grid.getItems()
Returns all items with their current positions and sizes.
const items = grid.getItems()
// [{ id, x, y, w, h, ... }]grid.layout()
Forces a layout recalculation. Useful after container resize.
window.addEventListener('resize', () => grid.layout())grid.destroy()
Removes all event listeners and cleans up. Call on unmount.
grid.destroy()Options
Pass to GridKit.create() as the second argument. All features are opt-in.
| Option | Type | Default | Description |
|---|---|---|---|
| collision | boolean | false | Enable collision detection and auto-push |
| animate | boolean | false | Animate item transitions |
| bounds | boolean | false | Constrain items within container |
| gap | number | 0 | Gap between items in pixels |
| padding | number | 0 | Container inner padding |
| resizeHandles | 'all' | Direction[] | 'all' | Which handles to show |
| onChange | (items) => void | undefined | Called when any item changes position/size |
Events
Subscribe via options callbacks.
onDragStart(item, event)Fired when dragging begins
onDrag(item, event)Fired continuously during drag
onDragEnd(item, event)Fired when dragging ends
onResizeStart(item, edge, event)Fired when resizing begins
onResize(item, edge, event)Fired continuously during resize
onResizeEnd(item, edge, event)Fired when resizing ends
onChange(items)Fired after any layout change
Styling
GridKit applies minimal styles. Target items with data attributes.
/* Target any grid item */
[data-gridkit-id] {
border-radius: 8px;
background: #1a1a2e;
border: 1px solid #292d30;
}
/* Style resize handles */
[data-gridkit-handle] {
opacity: 0;
transition: opacity 0.2s;
}
[data-gridkit-id]:hover [data-gridkit-handle] {
opacity: 1;
}
/* Style drag zone */
[data-gridkit-drag] {
cursor: grab;
}Framework Guides
React
import { useRef, useEffect } from 'react'
import { GridKit } from 'gridkit-layout'
function Dashboard() {
const containerRef = useRef(null)
useEffect(() => {
const grid = GridKit.create(containerRef.current, {
collision: true,
animate: true
})
grid.add({ id: '1', x: 0, y: 0, w: 300, h: 200 })
return () => grid.destroy()
}, [])
return <div ref={containerRef} style={{ width: '100%', height: '600px' }} />
}Angular
import { Component, ViewChild, ElementRef, AfterViewInit, OnDestroy } from '@angular/core'
import { GridKit } from 'gridkit-layout'
@Component({
selector: 'app-dashboard',
template: '<div #container style="width:100%;height:600px"></div>'
})
export class DashboardComponent implements AfterViewInit, OnDestroy {
@ViewChild('container') container!: ElementRef
private grid!: ReturnType<typeof GridKit.create>
ngAfterViewInit() {
this.grid = GridKit.create(this.container.nativeElement, { collision: true, animate: true })
this.grid.add({ id: '1', x: 0, y: 0, w: 300, h: 200 })
}
ngOnDestroy() { this.grid.destroy() }
}Vue
<script setup>
import { ref, onMounted, onUnmounted } from 'vue'
import { GridKit } from 'gridkit-layout'
const container = ref(null)
let grid
onMounted(() => {
grid = GridKit.create(container.value, { collision: true, animate: true })
grid.add({ id: '1', x: 0, y: 0, w: 300, h: 200 })
})
onUnmounted(() => grid?.destroy())
</script>
<template>
<div ref="container" style="width:100%;height:600px" />
</template>Examples
Save & Restore Layout
const grid = GridKit.create('#app', {
onChange: (items) => {
localStorage.setItem('layout', JSON.stringify(items))
}
})
// Restore on load
const saved = JSON.parse(localStorage.getItem('layout') || '[]')
saved.forEach(item => grid.add(item))Dynamic Add/Remove
document.getElementById('add-btn').onclick = () => {
grid.add({
id: crypto.randomUUID(),
x: 0, y: 0,
w: 200, h: 150,
content: createWidgetElement()
})
}
document.getElementById('remove-btn').onclick = () => {
const items = grid.getItems()
if (items.length) grid.remove(items[items.length - 1].id)
}