The graphic shows the final result of the guide, allowing you to freely drag tasks between columns.

Building a Simple Kanban Board with Drag and Drop in Vue 3 and Tailwind CSS — Part 1

Adrian Generous
4 min readFeb 12, 2024

--

This article is part of a series.
Part 2: Adding New Tasks”

In today’s programming world, Vue 3 combined with Tailwind CSS offers incredibly powerful tools for creating responsive and interactive user interfaces. One commonly encountered feature in project management applications is the Kanban board. While there are many ready-made plugins and libraries offering extensive functionalities, they can be overwhelming for beginners or those in need of a quick and straightforward solution. In this series of articles, we will focus on creating a simple Kanban board with drag and drop functionality using Vue 3 and Tailwind CSS.

Why Build from Scratch?

Although ready-made solutions can save time, building from scratch provides a better understanding of how individual components work and allows for greater flexibility in customizing features to meet your needs. Moreover, for those new to Vue and Tailwind, it’s an excellent opportunity to learn and practice.

Scope of the Article

In this article, we will not cover setting up a Vue 3 and Tailwind CSS environment, as there are already many excellent guides on this topic. Instead, we will focus on presenting and discussing the three key components that make up our Kanban board: KanbanBoard, KanbanColumn, and KanbanCard.

Component Structure

Our Kanban board will consist of three main components:

  1. KanbanBoard — the main component that manages the entire board layout.
  2. KanbanColumn — represents a single column on the Kanban board, where cards will be placed.
  3. KanbanCard — a single task card that can be dragged and dropped between columns.

Step 1: Creating the KanbanBoard Component

The KanbanBoard component acts as a container for columns and cards. In this example, we assume a simple data structure that stores cards in various columns, based on reactive Vue state.

The KanbanBoard component is the heart of our Kanban board. It serves as the main container for all columns and manages the state of the cards. It is responsible for initializing data and passing the appropriate cards to each column based on their status.

<template>
<div class="flex justify-around p-5 bg-gray-100 min-h-screen">
<KanbanColumn
v-for="status in columnStatuses"
:key="status"
:status="status"
:cards="cards.filter(card => card.status === status)"
@moveCard="moveCard"
></KanbanColumn>
</div>
</template>

<script setup>
import { ref } from 'vue';
import KanbanColumn from './KanbanColumn.vue';
const cards = ref([
{ id: 1, title: 'Task 1', status: 'New' },
// Add more cards with various statuses
]);
const columnStatuses = ['New', 'To Do', 'In Progress', 'Done'];
const moveCard = (cardId, newStatus) => {
const card = cards.value.find(card => card.id === cardId);
if (card) {
card.status = newStatus;
}
};
</script>

Structure:

  • Uses template to define the layout of the board, utilizing Tailwind CSS for styling.
  • Inside the component, we iterate through column statuses (New, To Do, In Progress, Done) and render a KanbanColumn component for each, passing filtered cards to it.

Key Points:

  • Reactive state of cards: We use ref from the Composition API to track the state of the cards. This ensures that when a card changes its status, the view is automatically updated.
  • Passing data to columns: Each column receives cards that belong to its status. Filtering is done using the filter method on the array of cards.

The KanbanColumn Component

KanbanColumn represents a column on the Kanban board. It is responsible for displaying cards assigned to its status and handles the logic for dragging and dropping.

<template>
<div
class="kanban-column bg-white shadow rounded p-4 flex-1 mx-2"
@dragover.prevent
@drop="drop($event)"
>
<h2 class="font-bold mb-2">{{ status }}</h2>
<KanbanCard
v-for="card in cards"
:key="card.id"
:card="card"
></KanbanCard>
</div>
</template>

<script setup>
import { defineProps, defineEmits } from 'vue';
import KanbanCard from './KanbanCard.vue';
const props = defineProps({
status: String,
cards: Array,
});
const emit = defineEmits(['moveCard']);
const drop = event => {
const cardId = event.dataTransfer.getData('text/plain');
emit('moveCard', parseInt(cardId, 10), props.status);
};
</script>

Structure:

  • Defines an area that can accept cards through dragging.
  • Uses dragover and drop events to enable dropping cards into the column.
  • Renders KanbanCard components for each card that belongs to the column.

Key Points:

  • Handling Drag & Drop Events: Capturing dragover prevents the browser's default behavior, allowing for dropping. The drop event uses DataTransfer to identify the dragged card and emits a moveCard event, updating the state in KanbanBoard.
  • Declarative Reactivity: Vue 3 reactively updates the UI in response to state changes, enabling smooth dragging and dropping of cards between columns.

The KanbanCard Component

The KanbanCard component is an individual card that can be dragged between columns. It represents a task or item on the Kanban board.

<template>
<div
class="kanban-card bg-gray-100 rounded shadow p-3 mb-2 cursor-pointer"
draggable="true"
@dragstart="dragStart($event, card)"
>
{{ card.title }}
</div>
</template>

<script setup>
import { defineProps } from 'vue';
const props = defineProps({
card: Object,
});
const dragStart = (event, card) => {
event.dataTransfer.setData('text/plain', card.id);
};
</script>

Structure:

  • Contains basic information about the card, such as the title.
  • Is draggable, meaning it can be dragged.

Key Points:

  • Initiating Dragging: The draggable attribute, combined with the dragstart event, allows for the initiation of the dragging process. In the dragstart event, the card's identifier is attached to DataTransfer, enabling its identification during dropping.
  • Styling: Styling with Tailwind CSS ensures a consistent and aesthetic look for the cards.

Summary

We have outlined the basic steps needed to build a simple Kanban board with drag and drop functionality using Vue 3 and Tailwind CSS. In future parts of the series, we will add more features such as editing, adding new cards, API integration, and UX/UI optimizations. Remember, this approach is meant to teach the basics and offers a solid foundation for further development of your own projects.

--

--

Adrian Generous

I navigate between coding & marketing, experienced as a CTO, project manager, & ad agency owner. I share Laravel & more on Medium, also a history enthusiast.