Vue Grid Layout v3
vue-grid-layout-v3 is a comprehensive and responsive grid layout system for Vue.js, enabling draggable and resizable widgets within a grid structure. It is heavily inspired by React-Grid-Layout and provides features such as static widgets, bounds checking during dragging and resizing, the ability to add or remove widgets dynamically, layout serialization, and automatic RTL support. The package specifically targets Vue 3.2+ environments, with the current stable version being 3.1.2. It maintains an active release cadence, providing minor updates and bug fixes for the 3.x branch. Key differentiators include its robust feature set for creating interactive dashboards and configurable layouts, making it a powerful tool for applications requiring dynamic user interfaces, and its clear lineage from a popular React library. This version represents a modern adaptation for the Vue 3 ecosystem, distinct from earlier versions supporting Vue 1 and Vue 2.
Common errors
-
[Vue warn]: Failed to resolve component: GridLayout
cause The `GridLayout` or `GridItem` components were not properly imported or registered in your Vue application.fixEnsure you `import { GridLayout, GridItem } from 'vue-grid-layout-v3';` and register them in your component's `components` option, or globally via `app.component('GridLayout', GridLayout)`. -
TypeError: Cannot read properties of undefined (reading 'emitter')
cause This error often occurs after upgrading from `vue-grid-layout-v3` v3.0 to v3.1 if you were accessing the `emitter` property from the component's exposed data, as the structure of exposed properties changed.fixReview the breaking changes documentation. If you're accessing exposed properties, update your code to reflect the new structure. For `GridLayout`, `emitter` is still exposed but the overall exposed object changed from `{ placeholderRef, emitter }` to `{ el, placeholderEl, emitter, placeholder }`. -
Cannot read properties of null (reading 'offsetWidth')
cause This can happen if the grid layout component attempts to calculate dimensions before its DOM element is fully rendered or available, often during initial component mounting or rapid state changes.fixEnsure the parent container has defined dimensions and that `GridLayout` is rendered within an existing element. Consider using `v-if` or `v-show` with a condition that ensures data readiness before rendering the grid, or use `nextTick` if manipulating layout after data changes.
Warnings
- breaking Upgrading from `vue-grid-layout-v3` version 3.0 to 3.1 introduces breaking changes in the exposed properties of `GridLayout` and `GridItem` components. Ensure your component references and prop destructuring are updated.
- gotcha This package (`vue-grid-layout-v3`) is specifically for Vue 3. Using it with Vue 2.x or Vue 1.x will lead to compatibility issues and runtime errors. Separate versions of the library exist for legacy Vue environments.
- gotcha Resizing does not work correctly with RTL (Right-to-Left) layouts in specific older versions of `vue-grid-layout`. While v3 generally supports RTL, this was a known issue in earlier versions.
Install
-
npm install vue-grid-layout-v3 -
yarn add vue-grid-layout-v3 -
pnpm add vue-grid-layout-v3
Imports
- GridLayout
const GridLayout = require('vue-grid-layout-v3')import { GridLayout } from 'vue-grid-layout-v3' - GridItem
import GridItem from 'vue-grid-layout-v3/GridItem.vue'
import { GridItem } from 'vue-grid-layout-v3' - App
import Vue from 'vue';
import { createApp } from 'vue'; import App from './App.vue';
Quickstart
import { createApp, ref } from 'vue';
import { GridLayout, GridItem } from 'vue-grid-layout-v3';
const app = createApp({
components: {
GridLayout,
GridItem,
},
setup() {
const layout = ref([
{ x: 0, y: 0, w: 2, h: 2, i: '0', static: false },
{ x: 2, y: 0, w: 2, h: 4, i: '1', resizable: true },
{ x: 4, y: 0, w: 2, h: 5, i: '2', draggable: true },
{ x: 6, y: 0, w: 2, h: 3, i: '3', minW: 2, maxW: 4 },
{ x: 8, y: 0, w: 2, h: 3, i: '4' },
{ x: 10, y: 0, w: 2, h: 3, i: '5' }
]);
const onLayoutUpdated = (newLayout) => {
console.log('Layout updated:', newLayout);
};
return {
layout,
onLayoutUpdated,
};
},
template: `
<div style="width: 100%; height: 500px; border: 1px solid #ccc; padding: 10px;">
<GridLayout
v-model:layout="layout"
:col-num="12"
:row-height="30"
:is-draggable="true"
:is-resizable="true"
:vertical-compact="true"
:use-css-transforms="true"
@layout-updated="onLayoutUpdated"
style="min-height: 400px;"
>
<GridItem
v-for="item in layout"
:x="item.x"
:y="item.y"
:w="item.w"
:h="item.h"
:i="item.i"
:key="item.i"
:is-draggable="item.draggable !== undefined ? item.draggable : true"
:is-resizable="item.resizable !== undefined ? item.resizable : true"
:static="item.static"
style="background-color: #f0f0f0; border: 1px solid #ddd; display: flex; align-items: center; justify-content: center;"
>
{{ item.i }}
</GridItem>
</GridLayout>
</div>
`
});
app.mount('#app');