Vue Draggable and Resizable Component
vue-drag-resize is a lightweight Vue.js component that enables elements to be made draggable and resizable within their parent container. It offers distinct versions for both Vue 2 (versions prior to 2.0.0, with `1.5.4` being a recent stable release in this line) and Vue 3 (versions 2.0.0 and above, with `2.0.3` being a recent stable for Vue 3). The library generally maintains an irregular release cadence, focusing on bug fixes and performance enhancements across its two major version tracks. Key differentiators include its zero external dependencies, fully reactive props, built-in support for touch events, grid snapping capabilities, options to maintain aspect ratio during resizing, strict confinement within parent boundaries, and the ability to restrict dragging or resizing to specific axes.
Common errors
-
Failed to resolve component: vue-drag-resize
cause The `vue-drag-resize` component has not been correctly registered with your Vue application.fixEnsure you have either globally registered it (`Vue.component('vue-drag-resize', VueDragResize)` for Vue 2 or `app.component('vue-drag-resize', VueDragResize)` for Vue 3) or locally within your parent component's `components` option, or directly imported and used in `<script setup>`. -
TypeError: Cannot read properties of undefined (reading 'width')
cause The `resizing` or `dragging` event handler is receiving an `undefined` or malformed `newRect` object, possibly due to incorrect event binding or an unexpected change in event payload.fixVerify that your event binding (`v-on:resizing="resize"`) is correct and that your `resize` method correctly expects and destructures the `newRect` object (e.g., `function resize(newRect) { this.width = newRect.width; }`) as shown in the documentation. -
Component is not draggable or resizable, or interaction is inconsistent.
cause The `isActive` prop is set to `false`, or `preventActiveBehavior` is `true` without external control of `isActive`, preventing user interaction. Alternatively, conflicting CSS might be interfering.fixEnsure `isActive` is set to `true` to enable interaction. If `preventActiveBehavior` is active, manage `isActive` via external application state. Also, check for any parent or sibling CSS properties like `pointer-events: none` or high `z-index` values that might obstruct interaction.
Warnings
- breaking Version 2.0.0 introduced official Vue 3 support, alongside a "completely redesigned code" and "improved performance." Users migrating from Vue 2 to Vue 3 (and upgrading this library from pre-2.0.0) should anticipate potential API changes or require adjustments to their component integration due to the underlying rewrite.
- breaking Even within the Vue 2 line, version 1.5.0 involved a "completely redesigned code" and "improved performance." While specific API breaks were not explicitly detailed, significant internal changes like this can introduce subtle behavioral differences or necessitate minor adjustments for users upgrading from versions prior to 1.5.0.
- gotcha For the component to correctly restrict movement and resizing within a parent element (using `parentLimitation`), it is crucial to either explicitly define the `parentW` and `parentH` props, or ensure the parent element itself has defined CSS dimensions (e.g., `width`, `height`) and `position: relative` that can be automatically calculated by the component. Without proper parent sizing, boundary constraints may not function as expected.
- gotcha The `isActive` prop controls whether the component is currently interactive (draggable/resizable). If `preventActiveBehavior` is `true`, the component will *not* automatically toggle its `isActive` state based on clicks inside or outside its area; `isActive` must then be controlled externally by your application logic.
Install
-
npm install vue-drag-resize -
yarn add vue-drag-resize -
pnpm add vue-drag-resize
Imports
- VueDragResize
import { VueDragResize } from 'vue-drag-resize';import VueDragResize from 'vue-drag-resize';
- Global Component Registration (Vue 2)
import VueDragResize from 'vue-drag-resize'; Vue.use(VueDragResize);
import Vue from 'vue'; import VueDragResize from 'vue-drag-resize'; Vue.component('vue-drag-resize', VueDragResize); - Global Component Registration (Vue 3)
import { createApp } from 'vue'; import Vue from 'vue'; import VueDragResize from 'vue-drag-resize'; const app = createApp(/* ... */); Vue.component('vue-drag-resize', VueDragResize);import { createApp } from 'vue'; import VueDragResize from 'vue-drag-resize'; const app = createApp(/* ... */); app.component('vue-drag-resize', VueDragResize);
Quickstart
<script setup>
import { ref } from 'vue';
import VueDragResize from 'vue-drag-resize';
const width = ref(200);
const height = ref(200);
const top = ref(50);
const left = ref(50);
function resize(newRect) {
width.value = newRect.width;
height.value = newRect.height;
top.value = newRect.top;
left.value = newRect.left;
}
</script>
<template>
<div id="app-container" style="width: 100%; height: 500px; border: 1px solid #ccc; position: relative;">
<VueDragResize
:isActive="true"
:w="width"
:h="height"
:x="left"
:y="top"
:minw="50"
:minh="50"
:parentLimitation="true"
v-on:resizing="resize"
v-on:dragging="resize"
style="background-color: #f0f0f0; border: 1px dashed #999; display: flex; flex-direction: column; justify-content: center; align-items: center;"
>
<h3>Hello Draggable World!</h3>
<p>Position: {{ top }} х {{ left }} </p>
<p>Size: {{ width }} х {{ height }}</p>
<p>Try dragging or resizing me!</p>
</VueDragResize>
</div>
</template>
<style>
#app-container {
font-family: Avenir, Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
}
</style>