🎄 Get 20% off from our JavaScript course for the holidays! 🎄
How to Create Native Drag and Drop Functionality in JavaScript

How to Create Native Drag and Drop Functionality in JavaScript

Improving user experience with intuitive interaction design
Ferenc AlmasiLast updated 2021 November 11 • Read time 7 min read
Drag and drop functionality is a common feature. It creates a more intuitive user flow. Learn how you can implement it in JavaScript
  • twitter
  • facebook
JavaScript

Learning React? Check out how you can achieve the functionality using hooks.

Drag and drop functionality is a common feature. It creates a more intuitive user flow by letting users grab and drop objects to places where they want them to be. There are countless of JavaScript libraries out there just for this purpose. Including one for every possible framework. However, this can be done quite simply with the native Drag and Drop API. This is what we will take a look at.

At the end of this tutorial, you will learn how to create the following drag and drop functionality for a Kanban board:

The output of this tutorial, drag and drop Kanban board

Setting Up the DOM

Let’s start by setting up the DOM first. Create an index.html file at your project’s root folder and add the following:

Copied to clipboard! Playground
<main class="board">
    <div class="column column-todo">
        <h2>Todo</h2>
        <article class="card">
            <h3>Todo #1</h3>
        </article>
        <article class="card">
            <h3>Todo #2</h3>
        </article>
        <article class="card">
            <h3>Todo #3</h3>
        </article>
    </div>
    <div class="column column-ip">...</div>
    <div class="column column-done">...</div>
</main>

<script src="drag-n-drop.js"></script>
index.html

The same structure will be true for the other two columns, “In Progress” and “Done”. As you can see, at the end of the body the drag-n-drop.js will handle the Drag & Drop functionality.

Adding drag and drop attributes

In order to work with Drag & Drop, however, we first need to decorate our DOM tree with additional attributes.

Copied to clipboard! Playground
<div class="column column-todo" ondrop="drop(event)" ondragover="allowDrop(event)">
    <h2>Todo</h2>
    <article class="card" draggable="true" ondragstart="drag(event)" data-id="1">
        <h3>Todo #1</h3>
    </article>
    <article class="card" draggable="true" ondragstart="drag(event)" data-id="2">
        <h3>Todo #2</h3>
    </article>
    <article class="card" draggable="true" ondragstart="drag(event)" data-id="3">
        <h3>Todo #3</h3>
    </article>
</div>
index.html

The other two columns will get the exact same attributes. Except for data-id. We need to have a unique ID for each article. This is what will use as a hook in JavaScript. Let’s see what each of the attributes are doing:

  • ondrop: This event will be fired when we drop an element on a valid drop target. This is where we want to handle dropping functionality.
  • ondragover: Whenever we drag an item over a drop area, this will gets fired, every few hundred milliseconds. Since this is called a lot, it’s important that we avoid placing calculation-heavy functions here.
  • draggable: This attribute sets whether an element can be dragged.
  • ondragstart: This event will be fired when a user starts to drag an element.
  • data-id: Will be using this attribute for identification. Every draggable element needs to be identifiable in some way. It’s recommended to either use ids or custom data attributes for this. In any case, each entry needs a unique name.
The grabbing mouse effect created with CSS

At this stage, the elements are now draggable. With the help of some CSS, we can set up different cursor icons to indicate whenever we grab an item.

Copied to clipboard! Playground
.card {
    cursor: grab;
}

.card:active {
    cursor: grabbing;
}
style.css
To achieve the effect, we only need to change the cursor property when the element is active.

Dragging Elements

Now that we have everything set up, we can start writing the functionality for dragging elements. First, you should always provide some visual feedback to the user about an action. When the user drags an item, we want to indicate that.

Animation when dragging elements

We can do this by adding an extra class to the element when we want to move it. To do that, add the following functions to your drag-n-drop.js:

Copied to clipboard! Playground
const dragStart = event => {
    event.currentTarget.classList.add('dragging');
};

const dragEnd = event => {
    event.currentTarget.classList.remove('dragging');
};

document.querySelectorAll('.card').forEach(card => {
    card.addEventListener('dragstart', dragStart);
    card.addEventListener('dragend', dragEnd);
});
drag-n-drop.js
Note that unlike in HTML, here you need to omit the “on” word from the name of event listeners

This will add two event listeners to each card. Note that in order to use array methods, you may have to convert the NodeList you get back from querySelectorAll, to an array. At the time of writing, support is around 93%. And what do these events do?

  • dragstart: This event will be fired when the user starts dragging an item.
  • dragend: This event will be fired when the user stops dragging the item. This means, the user either released pressing a mouse button or the Esc key was hit.
giving visual feedback to the user when dragging items
Whenever an item is dragged, the dragging class is applied

And what does the dragging class does to the card? It sets the opacity and the scale to 80%.

Copied to clipboard! Playground
.card {
    transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.card.dragging {
    opacity: .5;
    transform: scale(.8);
}
style.css
It’s important to add a transition property to make the animation smooth.

What will make drag and drop work?

While here, let’s also set up the drag function which will be fired on every dragstart event. The sole responsibility of this function is to set up some data that we can later use when the item is dropped.

Copied to clipboard!
const drag = event => {
    event.dataTransfer.setData('text/html', event.currentTarget.outerHTML);
    event.dataTransfer.setData('text/plain', event.currentTarget.dataset.id);
};
drag-n-drop.js

The dataTransfer object can hold data about the dragged object. The setData method takes two parameters: a mime-type and a payload. Here we want to store the HTML content of the dragged element as well as its id. To make things work, we want to:

  • Add this HTML to the new column when we drop it. We will use the outerHTML content for this.
  • Remove the original element from the original column. We will use the id for this.
Looking to improve your skills? Check out our interactive course to master JavaScript from start to finish.
Master JavaScript Remove ads

Dropping Elements

Now we can move onto dropping the items. Again, let’s start first by adding some visual cues to the user when they drag the card over a column.

Copied to clipboard! Playground
const dragEnter = event => {
    event.currentTarget.classList.add('drop');
};

const dragLeave = event => {
    event.currentTarget.classList.remove('drop');
};

document.querySelectorAll('.column').forEach(column => {
    column.addEventListener('dragenter', dragEnter);
    column.addEventListener('dragleave', dragLeave);
});
drag-n-drop.js

This time, we want to use the dragenter and dragleave events. Very similar to dragstart and dragend, but they have different purposes.

  • dragenter: This event will be fired when a draggable element enters a valid drop area.
  • dragleave: This event will be fired when a draggable element leaves a valid drop area.
Highlighting columns when dragging items over it
Dragging the item over a column will highlight it with a dashed border.

From CSS side, we need to set transition again, as well as adding a dashed border.

Copied to clipboard! Playground
.column {
    transition: all 0.3s cubic-bezier(0.4, 0.0, 0.2, 1);
}

.column.drop {
    border: 2px dashed #FFF;
}

.column.drop article {
    pointer-events: none;
}
style.css

Another important thing is to remove the pointer-events from the cards. This will let the column receive all events and get the dashed border, even if we drag the card over another card.

All that’s left to do is to actually add the items to the new column. For this, we will need two extra functions:

Copied to clipboard! Playground
const drop = event => {
    document.querySelectorAll('.column').forEach(column => column.classList.remove('drop'));
    document.querySelector(`[data-id="${event.dataTransfer.getData('text/plain')}"]`).remove();

    event.currentTarget.innerHTML = event.currentTarget.innerHTML + event.dataTransfer.getData('text/html');
};

const allowDrop = event => {
    event.preventDefault();
};
drag-n-drop.js

The allowDrop function is used for preventing the default behavior of the browser, so we can actually drop the item into the column.

In the drop function, we first want to remove the drop class from everywhere (which is responsible for the dashed border). Then we can use the data we set with dataTransfer.setData. In order:

  • We remove the original card that we select based on its data-id attribute.
  • We append the new card to the end of the column.
Dragging and dropping items

Summary

And that’s it! You’ve just created your very first Kanban board with drag and drop functionality. If you would like to learn more about the native drag and drop API, make sure to check out the official docs of MDN web docs. It includes all available drag events that you can use in different phases of the drag and drop lifecycle.

If you would like to play around with the finished product, you can clone it from this GitHub repository. Have you used the Drag and Drop API before? Let us know your thoughts in the comments down below! Thank you for taking the time to read this article, happy coding!

5 Best Practices for Clean JavaScript
Did you find this page helpful?
📚 More Webtips
Frontend Course Dashboard
Master the Art of Frontend
  • check Access exclusive interactive lessons
  • check Unlimited access to hundreds of tutorials
  • check Remove ads to learn without distractions
Become a Pro

Recommended