Drag And Drop In Vue.js With Vue.Draggable

Vue Draggable Cover

Adding some drag and drop functionality to an application can greatly enhance the user experience. However, creating such a feature from scratch on your own may pose a significant challenge. Fortunately, there are a few libraries that make this task as easy as pie. Thank God for those hard working bees 🐝.

In this article, we’ll be specifically looking at Vue.Draggable, which is a Vue.js specific implementation of Sortable.js. At the time of this writing, it’s the most popular drag and drop library for Vue.js. Please note that the version of Vue.Draggable under consideration applies to Vue.js 2.x! 🚨


We can install Vue.Draggable in our project with npm or Yarn.

yarn add vuedraggable

npm i -S vuedraggable

After installing the library, we have to import it into our component(s) as follows:

import draggable from 'vuedraggable';

export default {
  components: {

Regular Usage

What makes Vue.Draggable so great is its ability to easily integrate with any UI components, whether it be from Vuetify or Bootstrap Vue. All you have to do is wrap your draggable elements in a <draggable> tag. And that’s all there is to it! 😲 However, at a bare minimum you’ll want to insert a v-model attached to an array with relevant data. Otherwise, your array won’t update to any visual changes.

So far, we can only drag and drop items in their own array, but not across others (unless it is nested). In order to do so we need to add the options prop from Sortable.js, to which will assign the following object: { group:'clothes' }. What you name the group property is irrelevant. However, any list of items you’d like to drag between should share the same name.

The code snippet below is an example of what was just discussed.

    <h2>My Clothing List</h2>
    <draggable v-model="tshirtList" :options="{group:'clothes'}">
      <div v-for="tshirt in tshirtList" :key="tshirt">
        {{ tshirt }} 
    <draggable v-model="pantsList" :options="{group:'clothes'}">
      <div v-for="pants in pantsList" :key="pants">
        {{ pants }}


While working with multiple lists, you may come across a gotcha moment when trying to drop an item on an empty list. You can easily fix this issue by setting a minimum height for the <draggable> component. Crisis averted… πŸ˜…

Vuex Usage

If you’re working on a larger project, chances are that you’re using Vuex. What you’ll quickly discover is that v-model isn’t compatible with Vuex. This is something I’ve covered in a previous article titled How To Use V-Model With Vuex. In order to mend this problem, you can simply add the code seen below:

computed: {
  tshirtList: {
    get() {
      return this.$store.state.tshirtList
    set(value) {
      this.$store.commit('updateList', value)

Props & Events


Vue.Draggable provides a host of props that you can use to configure your drag and dropness. 😎

  • value: Input array to the draggable component used with v-model. The array is immutable, thus recreated on each change,
  • list: Alternative to theΒ value prop with a mutable array updated through the splice method,
  • options: Used to initialise the sortable object,
  • element: HTML tag type that the draggable component turns into upon compilation. Always defaults to div,
  • clone: Function called on the source component to clone an element when it returns true,
  • move: Cancels drag operation if function returns false, and
  • componentData: Used to set props or events to the child component declared by the element props.

For more details on the props, check out their documentation.


To sweeten the deal even more with this library, Vue.Draggable supports the following Sortable.js events:


Details on their implementation can be referenced from their documentation as well.

Explore the possibilites

There are two demos of Vue.Draggable, which you can access here and here, that show you the many features of the library, several of which I haven’t covered. Why not give them a try and see what’s possible?

Leave a Comment

Your email address will not be published. Required fields are marked *