Official Vue 3 wrapper for GridStack.js.
Mirrors the gridstack-react wrapper API while feeling native to Vue:
Composition API, provide/inject, composables, and <Teleport> for zero-destroy widget reparenting.
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')<!-- App.vue -->
<script setup lang="ts">
import { defineComponent, h } from 'vue'
import { GridStack, type GridStackOptions } from 'gridstack/dist/vue'
import 'gridstack/dist/gridstack.css'
const Text = defineComponent({
props: { content: { type: String, default: '' } },
setup(props) { return () => h('div', props.content) },
})
const options: GridStackOptions = {
cellHeight: 50,
children: [
{ id: 'a', x: 0, y: 0, w: 3, h: 2, component: 'Text', props: { content: 'Hello!' } },
],
}
</script>
<template>
<GridStack :options="options" :components="{ Text }" />
</template>| Prop | Type | Description |
|---|---|---|
options |
GridStackOptions |
GridStack init options, including children for the initial layout |
components |
ComponentMap |
Map component string keys → Vue components |
Emits: added, change, removed, drag, dragstart, dragstop, dropped, resize, resizestart, resizestop
Exposed: getGrid() → GridStack | null (for imperative access via template ref)
Default slot: rendered outside the .grid-stack div — use for toolbars, debug panels, etc.
<GridStack :options="opts" :components="comps">
<Toolbar /> <!-- rendered beside the grid, not inside it -->
</GridStack>Composable for children of <GridStack>:
const { grid, addWidget, removeWidget, removeAll, save, load, layoutVersion } = useGridStack()Composable for components rendered inside a widget slot:
const { id, node } = useGridStackItem()
// node is the live GridStackNode (position, size, etc.)Persist extra widget state into grid.save():
const count = ref(0)
useWidgetSerializer({
serialize: () => ({ count: count.value }),
// deserialize: (data) => { count.value = data.count } // optional
})Widgets are described by GridStackWidget objects (extends the core type):
interface GridStackWidget {
id?: string
x?: number; y?: number; w?: number; h?: number
component?: string // key in the `components` map
props?: Record<string, unknown> // passed as props to the component
subGridOpts?: GridStackOptions // for nested sub-grids
// ... all standard GridStack widget options
}Widget components are mounted once and survive being dragged between grids.
<GridStackItem> uses Vue's <Teleport> to move slot content into whichever
.grid-stack-item-content element currently owns the widget — no destroy/remount.
cd vue
npm install
npm run dev # Vite dev server (demo app)
npm run build # production build of the demo
npm run build:lib # compile the library to dist/vue/
npm run test # vitest| Angular | Vue | |
|---|---|---|
| Component key | selector |
component |
| Component data | input |
props |
| Serialization | BaseWidget.serialize() |
useWidgetSerializer() (or BaseWidget) |
| Context | @Input() / DI |
provide/inject + composables |
| DOM injection | ViewContainerRef |
<Teleport> |