A drag-and-drop Kanban board built with Vue 3 and Pinia. Designed to be minimal, customizable, and smooth like butter 🧈.
⚡ Perfect for task management, sprints, or project boards inside Vue apps.
npm install kanvue
npm install pinia
<!-- main.ts -->
import { createPinia } from "pinia";
import { createApp } from "vue";
import App from "./App.vue";
import "./style.css";
// ✅ Step 1: create Vue app
const app = createApp(App);
// ✅ Step 2: create pinia instance
const pinia = createPinia();
// ✅ Step 3: register Pinia into Vue app
app.use(pinia);
// ✅ Step 4: manually provide it for `inject("pinia")` to work in external libraries
app.provide("pinia", pinia); // ⭐️ THIS IS IMPORTANT
// ✅ Step 5: mount your app
app.mount("#app");
<!-- App.vue -->
<template>
<div class="main-container">
<Kanban
:data="initialData"
@drop-end="handleDrop"
@drag-start="handleDragStart"
>
<template #card="{ task }">
<div >
<h6 class="title">{{ task.title }}</h6>
<p class="description">Status: {{ task.status }}</p>
<p class="description">Priority: {{ task.priority }}</p>
</div>
</template>
</Kanban>
</div>
</template>
<script setup>
import Kanban from "kanvue";
import initialData from "./data";
function handleDrop(payload) {
console.log("Dropped:", payload);
}
function handleDragStart(el) {
console.log("Drag start:", el);
}
</script>
const data = [
{
id: "123",
title: "To Do",
tasks: [
{
id: "opl",
title: "🧠 Brainstorm new app ideas",
status: "Todo",
},
{
id: "jkl",
title: "🎨 Design cute splash screen",
status: "Todo",
},
{
id: "fgh",
title: "💌 Write welcome email",
status: "Todo",
},
],
},
{
id: "345",
title: "In Progress",
tasks: [
{
id: "asd",
title: "🛠️ Setup project boilerplate",
status: "In Progress",
},
{
id: "zxc",
title: "📦 Install Vue + Vite",
status: "In Progress",
},
],
},
{
id: "678",
title: "Done",
tasks: [],
},
{
id: "901",
title: "Later",
tasks: [
{
id: "cvx",
title: "📱 Mobile responsive polish",
status: "Later",
},
{
id: "bnm",
title: "💬 Add chatbot widget",
status: "Later",
},
],
},
];
export default data;
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main-container {
background-color: #ffffff;
height: 100vh;
display: flex;
justify-content: center;
padding: 2rem 0rem;
gap: 0.9rem;
}
.vue-kanban-main-container {
display: flex;
gap: 1rem;
}
.column {
width: 350px;
color: white;
padding-top: 0;
border: 2px black dashed;
border-radius: 1rem;
border-width: 0.3rem;
max-height: fit-content;
}
.column .column-title {
position: sticky;
top: 0;
background-color: #ffffff;
z-index: 1;
/* padding: 1rem; */
height: 4rem;
display: flex;
align-items: center;
justify-content: center;
}
.column h3 {
text-align: center;
color: black;
font-size: 1.4rem;
font-family: "Courier New", Courier, monospace;
font-weight: 600;
/* color: rgb(255, 255, 255); */
/* text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.3); */
}
/* scrollbar */
.column::-webkit-scrollbar {
width: 8px;
}
.column::-webkit-scrollbar-thumb {
background: #888;
border-radius: 2px;
}
.card-container {
overflow-y: auto;
scrollbar-width: thin; /* Makes it thin */
scrollbar-color: rgba(255, 255, 255, 0.3) transparent; /* thumb | track */
scroll-behavior: smooth;
height: fit-content;
max-height: calc(100% - 4rem); /* prevent overflow */
}
.card {
background-color: rgb(255, 255, 255);
padding: 1rem;
color: white;
font-size: 1.5rem;
border-radius: 1rem;
box-shadow: 0px 0px 20px 5px rgba(58, 58, 61, 0.149);
text-align: center;
font-family: "Courier New", Courier, monospace;
font-weight: 600;
color: rgb(17, 16, 16);
text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.3);
margin: 0 1rem;
}
.card .title {
font-size: 1.2rem;
font-weight: 600;
color: rgb(17, 16, 16);
margin-bottom: .7rem;
}
.card .description {
font-size: 0.9rem;
color: rgb(17, 16, 16);
margin-bottom: .7rem;
}
.card:active {
opacity: 0.5;
}
::view-transition-old(card-*) {
animation-duration: 0.6s;
animation-timing-function: ease-in-out;
}
::view-transition-new(card-*) {
animation-duration: 0.6s;
animation-timing-function: ease-in-out;
}
.drop-area {
height: 19rem;
transition: background-color 0.3s ease, height 0.3s ease;
}
Prop | Type | Description |
---|---|---|
data |
object |
The Kanban board data (columns + tasks) |
drop-end |
function |
Callback when a task is dropped |
drag-start |
function |
Callback when a task starts dragging |
git clone https://github.com/NidhiSharma63/vue-kanban.git
cd kanvue
npm install
npm run dev
Made with ❤️ by Nidhi Sharma
📄 License MIT