Trello-Style Drag and Drop Using Vue-Smooth-Dnd

Vishwanath Sastry
Oct 17 · 5 min read
Image for post
Image for post

Drag and drop is one of the most helpful features in tons of applications.

Be it a task-list, note-taking, todo-list or a project management tool like Trello, drag and drop is a fantastic feature that makes things quite seamless.

I was always fascinated with Trello’s UI, and even made an attempt to clone it using plain HTML & CSS without any interactions. I knew the next step was to learn drag and drop.

After a lot of Googling, I came across vue-smooth-dnd, which is an amazing plugin!

There are tons of drag and drop tutorials, but what frustrated me the most was none of them implemented Trello-like animation. Especially the placeholder that’s shown from where the card was dragged from, and the “drop” placeholder, i.e. the area where the card is about to dropped in.

Thus, I took it upon myself to clone the exact animation, and could achieve it quite easily with vue-smooth-dnd

What We Will Do

To make our functionality similar to Trello, we will create a wrapper container, four vertical list containers and 2 cards in each list container, for now.
To keep the UI simple, we’ll use plain CSS + flex.

Pre-requisites

  1. vue.js installed with vue-cli

Functionality

The core functionality that we are focusing is not just simple drag and drop, but to also style & animate the transitions similar to Trello.

Let’s Get Started

For now, we need three main files;

  1. App.vue

We’ll tackle this problem, step by step;

  • Creating the basic layout

Lets install vue-smooth-dnd first, by running the command;

npm i vue-smooth-dnd

For yarn users;

yarn add vue-smooth-dnd

Creating the basic layout

App.vue

Delete all the default code from your App.vue and replace it with the following below;

Our App.vue component comprises of the CardList.vue component, wherein we have repeated it multiple times to display multiple vertical lists. The Roboto font is used to make things look clean & minimal.

Here’s the index.html file for reference;

Next up, lets create the CardList.vue in the components folder.

Our CardList.vue component will comprise a vertical list, wherein we use Card.vue as our child component.

CardList.vue

Then, create Card.vue in the components folder.
Similar to App.vue, we have declared the Card component multiple times.

Card.vue

Alright, now comes the fun part.

Adding the default vue-smooth-dnd functionality

Lets import our Container & Draggable components from the vue-smooth-dnd plugin, and declare them in our template, after which our CardList.vue looks like this;

Don’t panic! This looks like a lot, but let me break it down;

  • We’ve imported our Container & Draggable components from the plugin. These components add the CSS classes necessary for the inbuilt drag and drop animation, and the Container component is where all the magic happens.

For instance, if we moved the first card in our first vertical list, the payload would be the following;

{
id: 0;
text: "List 1 Text 0";
}
  • We’ve used the group-name prop to drag and drop items from one list to another. Otherwise, we would be restricted to dragging and dropping in the same list.

From the docs;

:group-name: Draggables can be moved between the containers having the same group names. If not set container will not accept drags from outside.

  • The @drop=”onDrop” is where the actual drag and drop functionality happens.

What does the custom @drop event do? The docs explain it best;

@drop

The event to be emitted by any relevant container when drop is over. (After drop animation ends). Source container and any container that could accept drop is considered relevant.

@drop="onDrop('listOne', $event)"

Lets break down what is happening here;

  1. We send the name of our list as a parameter to the onDrop method, along with our DOM event using vue’s special $event variable.
onDrop(collection, dropResult) {
this[collection] = applyDrag(this[collection], dropResult);
}

Now what exactly does the dropResult param contain here? With typescript, things would’ve been explicit.

From the docs;

dropResult : object

removedIndex : number : index of the removed child. Will be null if no item is removed.

addedIndex : number : index to add dropped item. Will be null if no item is added.

payload : object : the payload object retrieved by calling get-child-payload function.

droppedElement : DOMElement : the DOM element that is moved

Here’s our applyDrag helper function that we had imported in our CardList.vue file

Remember, we had called this helper function in our onDrop method;

onDrop(collection, dropResult) {
this[collection] = applyDrag(this[collection], dropResult);
}

Great! Now, we can drag and drop in the same list or drag and drop from one list to another. All that’s left is the Trello-style drop placeholder, drag placeholder & the card-rotate animation.

Trello-like styling & animation

Here’s our updated CardList.vue file;

To style our dragged card & to add a drop placeholder, we’ve used the drag-class, drop-class & drop-placeholder props.

From the docs;

:drag-class: Class to be added to the ghost item being dragged. The class will be added after it's added to the DOM so any transition in the class will be applied as intended.

:drop-class: Class to be added to the ghost item just before the drop animation begins.

We use a simple rotateZ transform to rotate our dragged card like Trello does, and as soon as the card is about to be dropped, we rotate it back to 0 deg.

Since we’ve scoped our styles, adding the styles for the drop-preview class in our CardList.vue component won’t work.

We can instead add the styles for it in our App.vue class;

The Startup

Medium's largest active publication, followed by +729K people. Follow to join our community.

Vishwanath Sastry

Written by

Front-end engineer passionate about everything web-related.

The Startup

Medium's largest active publication, followed by +729K people. Follow to join our community.

Vishwanath Sastry

Written by

Front-end engineer passionate about everything web-related.

The Startup

Medium's largest active publication, followed by +729K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store