DEV Community

Cover image for Build an interactive kanban board with Vue Draggable
Sam Walpole
Sam Walpole

Posted on • Originally published at samwalpole.com

Build an interactive kanban board with Vue Draggable

Vue Draggable is a great library for Vue.js that makes it super simple to create interactive draggable components with virtually no effort. I have recently used it to create an interactive kanban board, in which tasks can be rearranged and moved between cards just by dragging.

Preview

So let's start by creating some reorderable cards! P.S I'm using Vuetify as the UI framework, in case the tags look unfamiliar.

<template>
  <v-container fluid>
    <v-row>
      <v-col class="text-right">
        <v-btn color="primary" depressed @click="addCard"> Add Card </v-btn>
      </v-col>
    </v-row>
    <v-row>
      <v-col v-for="(card, i) in cards" :key="i" cols="12" sm="6" md="4">
        <v-card outlined>
          <v-card-title>
            <v-text-field v-model="card.title"></v-text-field>
          </v-card-title>
        </v-card>
      </v-col>
    </v-row>
  </v-container>
</template>

<script>
export default {
  data: () => ({
    cards: []
  }),  
  methods: {
    addCard() {
      const card = {
        title: 'New Card',
        tasks: [],
      }

      this.cards.push(card)
    },
  }
}
</script>
Enter fullscreen mode Exit fullscreen mode

The code above should give you the ability to create cards by clicking the Add Card button, but they aren't draggable yet. First make sure that you have VueDraggable installed by running:

yarn add vuedraggable
Enter fullscreen mode Exit fullscreen mode

Then import VueDraggable into you component:

<script>
import Draggable from 'vuedraggable'

export default {
  components: {
    Draggable,
  },
  data: () => ({
    cards: []
  }),  
...
Enter fullscreen mode Exit fullscreen mode

Finally, all we need to do to make the cards draggable is to wrap the cards with the draggable component. In our case, we're replacing v-row with draggable.

<draggable :list="cards" group="cards" class="row">
  <v-col v-for="(card, i) in cards" :key="i" cols="12" sm="6" md="4">
...
Enter fullscreen mode Exit fullscreen mode

There are two attributes that are important to note. First, the list attribute defines the list of objects that should be draggable, in our case the cards array. Secondly, the group attribute is just a way of identifying groups of draggable components (you'll see why this is useful when we move on to creating draggable tasks).

Try running your project now. You should be able to create multiple cards, and reorder them by dragging!

Now let's move on to the tasks. Below the v-card-title tag we need to add the following code:

<v-card-text>
  <draggable :list="card.tasks" group="tasks" class="row">
    <v-col v-for="(task, j) in card.tasks" :key="j" cols="12">
      <v-text-field v-model="task.title">
        <template v-slot:append>
           <v-btn color="error" text class="ml-3" @click="deleteTask(i, j)"> Delete </v-btn>
        </template>
      </v-text-field>
    </v-col>

    <template v-slot:footer>
      <v-col cols="12">
        <v-btn color="primary" depressed block @click="addTask(card)"> Add Activity </v-btn>
      </v-col>
      <v-col cols="12">
        <v-btn color="error" text block @click="deleteCard(i)"> Delete Card </v-btn>
      </v-col>
    </template>
  </draggable>
  </v-card-text>
Enter fullscreen mode Exit fullscreen mode

Add the following in the script section:

methods: {
    deleteCard(index) {
      this.cards = [...this.cards.slice(0, index), ...this.cards.slice(index + 1)]
    },
    addTask(card) {
      const task = {
        title: 'New Activity'
      }

      card.tasks.push(task)
    },
    deleteTask(cardIndex, taskIndex) {
      const card = this.cards[cardIndex]
      card.tasks = [...card.tasks.slice(0, taskIndex), ...card.tasks.slice(taskIndex + 1)]
    }
}
Enter fullscreen mode Exit fullscreen mode

Here we've added the ability to add and delete tasks from each card, as well as delete the card itself. We've also added another draggable component, which wraps around each group of tasks. We've given it a group name of tasks. This is important because each list of tasks will have the same group name, meaning that we can drag tasks from one card to another! P.S. if you only wanted tasks to be reorderable within its own card, you would have to create a unique group name for each list of tasks.

And that's it! Hopefully this post has shown you how quick and easy it is to develop highly interactive draggable apps using the Vue Draggable library. What ideas will you use it for?

Conclusion

In this post I have shown you the basics of using the Vue Draggable library to create an interactive kanban board. The full repository can be found here on GitHub.

"Ten++ Ways to Make Money as a Developer" eBook

I post mostly about full stack .NET and Vue web development. To make sure that you don't miss out on any posts, please follow this blog and subscribe to my newsletter. If you found this post helpful, please like it and share it. You can also find me on Twitter.

Top comments (0)