Trello-Style Drag and Drop Using Vue-Smooth-Dnd (2024)

Trello-Style Drag and Drop Using Vue-Smooth-Dnd (3)

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

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.

  1. vue.js installed with vue-cli
  2. vue-smooth-dnd

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

For now, we need three main files;

  1. App.vue
  2. Card.vue
  3. CardList.vue
  • Creating the basic layout
  • Adding the default vue-smooth-dnd functionality
  • Trello-like styling & animation

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

npm i vue-smooth-dnd

For yarn users;

yarn add vue-smooth-dnd

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.

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;

  • 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.
  • Earlier, we hardcoded the card text in our Card component and declared our CardList component four times in our App.vue template. Now, that’s not necessary anymore. What we’ve basically done is created four different arrays; one for each vertical list. We’ve called them listOne, listTwo etc…
  • The entire object in each array is sent as props to the Card component.
  • We’ve used our get-child-payload prop to get the details about the card that we’re dragging and dropping.

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.
  2. We then use our applyDrag helper function to determine two things — where to remove the dragged element from, and where to add it(i.e. the area where it has been dropped); whether it is a separate list or dragged and dropped in the same list.
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.

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;

Trello-Style Drag and Drop Using Vue-Smooth-Dnd (2024)
Top Articles
Latest Posts
Article information

Author: Nicola Considine CPA

Last Updated:

Views: 5970

Rating: 4.9 / 5 (69 voted)

Reviews: 92% of readers found this page helpful

Author information

Name: Nicola Considine CPA

Birthday: 1993-02-26

Address: 3809 Clinton Inlet, East Aleisha, UT 46318-2392

Phone: +2681424145499

Job: Government Technician

Hobby: Calligraphy, Lego building, Worldbuilding, Shooting, Bird watching, Shopping, Cooking

Introduction: My name is Nicola Considine CPA, I am a determined, witty, powerful, brainy, open, smiling, proud person who loves writing and wants to share my knowledge and understanding with you.