Vue Grid Layout
Vue Grid Layout is a component library for Vue.js that provides a draggable and resizable grid layout system. It enables developers to create interactive dashboards and editable layouts where users can freely arrange, resize, and manage widgets. The current stable version, 2.4.0, supports Vue 2.2+. The library is actively maintained with a focus on bug fixes and incremental feature enhancements, without a strict release cadence. It offers features such as static widgets, bounds checking for drag and resize operations, layout serialization and restoration, automatic RTL support, and responsive design capabilities. It was heavily inspired by React-Grid-Layout. For Vue 3, there are community-maintained forks and dedicated libraries like `vue-grid-layout-v3`, `vue3-grid-layout`, and `@marsio/vue-grid-layout`, as the original `vue-grid-layout` does not officially support Vue 3.
Common errors
-
Resizing a grid item in RTL mode isn't working / Grid items are misaligned in RTL.
cause Older versions had a known bug where resizing functionality was broken for grid items in Right-to-Left (RTL) mode.fixUpgrade to `vue-grid-layout` version 2.3.10 or later, as this issue was specifically fixed in that release. -
Error: Cannot read property 'interactObj' of undefined
cause This error can occur when grid items are removed from the layout, and the underlying `interact.js` object associated with them is not properly cleaned up or is accessed after removal.fixThis bug was addressed in version 2.3.8. Ensure you are using `vue-grid-layout` version 2.3.8 or newer. Also, ensure that your `layout` array is updated correctly when items are added or removed. -
Grid item's size changes unexpectedly when hiding/displaying it again in responsive mode.
cause A regression in previous versions caused grid items to lose their correct dimensions when toggling their visibility in a responsive layout.fixUpdate to `vue-grid-layout` version 2.3.10 or later, where this specific bug was fixed. Ensure proper handling of `v-if` or `v-show` on `GridItem` components. -
Plugin installation fails or components are not registered globally.
cause Earlier versions (e.g., around 2.3.9) had a bug in the plugin installation mechanism, preventing components from being correctly registered when `Vue.use(VueGridLayout)` was called.fixUpgrade to `vue-grid-layout` version 2.3.9 or newer. If you need to support Vue 2.1.10 and below, use version 2.1.3 of `vue-grid-layout`.
Warnings
- breaking This package, `vue-grid-layout` (version 2.x), is designed for Vue 2 applications. It does not officially support Vue 3. Using it in a Vue 3 project will lead to compatibility issues and errors. Multiple community-maintained forks exist for Vue 3 compatibility, such as `vue-grid-layout-v3`, `vue3-grid-layout`, and `@marsio/vue-grid-layout`.
- breaking The package has specific version requirements for Vue.js. Version 2.4.0 supports Vue 2.2+. Older Vue versions require specific older releases of `vue-grid-layout` (e.g., 2.1.3 for Vue <= 2.1.10 and 1.0.3 for Vue 1.x).
- gotcha Responsive layout behavior and specific feature implementations have seen several fixes across minor versions. For instance, initial responsive layouts and breakpoint change events were added in 2.3.8, and a regression in responsive layout handling was fixed in 2.3.11. Item resizing might behave unexpectedly in responsive mode in older versions.
- deprecated The `resized` event, which is emitted when the container (e.g., browser window) changes size, was renamed from a previous, potentially inconsistent name in version 2.3.7. Using the old event name will not work or might lead to unexpected behavior.
- gotcha From version 2.3.10, `interact.js` (the underlying drag-and-resize library) is imported as ES6 modules. This change was implemented to optimize bundle size but might affect build configurations or environments that do not fully support ES6 modules or tree-shaking correctly.
Install
-
npm install vue-grid-layout -
yarn add vue-grid-layout -
pnpm add vue-grid-layout
Imports
- VueGridLayout
import { GridLayout, GridItem } from 'vue-grid-layout'; // This is for component-level import, not global plugin registration.import VueGridLayout from 'vue-grid-layout'; Vue.use(VueGridLayout);
- GridLayout, GridItem
const { GridLayout, GridItem } = require('vue-grid-layout'); // CommonJS syntax, less common in modern Vue 2 projects. import VueGridLayout from 'vue-grid-layout'; // This imports the default export for plugin installation, not individual components.import { GridLayout, GridItem } from 'vue-grid-layout';
Quickstart
<template>
<div id="app">
<h1>Vue Grid Layout Example</h1>
<GridLayout
:layout.sync="layout"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:vertical-compact="true"
:use-css-transforms="true"
:prevent-collision="false"
>
<GridItem
v-for="item in layout"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
@resized="resizedEvent"
@moved="movedEvent"
>
<span class="text">{{ item.i }}</span>
</GridItem>
</GridLayout>
</div>
</template>
<script>
import { GridLayout, GridItem } from 'vue-grid-layout';
export default {
components: {
GridLayout,
GridItem,
},
data() {
return {
layout: [
{ x: 0, y: 0, w: 2, h: 2, i: '0' },
{ x: 2, y: 0, w: 2, h: 4, i: '1' },
{ x: 4, y: 0, w: 2, h: 5, i: '2' },
{ x: 6, y: 0, w: 2, h: 3, i: '3' },
{ x: 8, y: 0, w: 2, h: 3, i: '4' },
{ x: 10, y: 0, w: 2, h: 3, i: '5' },
],
};
},
methods: {
resizedEvent(i, newH, newW, newHPx, newWPx) {
console.log(`Resized item ${i}, new H: ${newH}, new W: ${newW}`);
},
movedEvent(i, newX, newY) {
console.log(`Moved item ${i}, new X: ${newX}, new Y: ${newY}`);
},
},
};
</script>
<style>
#app {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
.vue-grid-item {
background-color: #f0f0f0;
border: 1px solid #ccc;
box-sizing: border-box;
}
.vue-grid-item .text {
font-size: 24px;
text-align: center;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
</style>