DEV Community

Rohit Sharma
Rohit Sharma

Posted on • Updated on

How to create a Drag and Drop interface using Vanilla JS

Hi! I'm back after a long break with a new post on how to create a Drag and Drop interface using Vanilla JS.

GitHub Repo

Let's have look what we are going to create in this tutorial

Drag and drop functionality is a great way to enhance the user experience of a web application. With drag and drop, users can easily move elements around a page, reorder lists, and perform other interactive actions. In this tutorial, we'll cover how to create a simple drag and drop interface with vanilla JavaScript.

We'll be using TailwindCSS for styling you may use pure CSS or any other CSS framework.

So, let's write the HTML for our project in index.html

HTML

<html>
<head>
       <title>Drag and Drop Example</title>
</head>
<body>
    <ul id="list">
        <li id="item1" draggable="true">Item 1</li>
        <li id="item2" draggable="true">Item 2</li>
        <li id="item3" draggable="true">Item 3</li>
        <li id="item4" draggable="true">Item 4</li>
        <li id="item5" draggable="true">Item 5</li>
    </ul>
  <div id="target"></div>
</body>
</html>
Enter fullscreen mode Exit fullscreen mode

Now add the Tailwind CDN in <head>and add classes to it

<!DOCTYPE html>
<html>
<head>
    <title>Drag and Drop Example</title>
    <!-- Load Tailwind CSS -->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.7/tailwind.min.css">

    <style>
        /* Add custom styles here */
    </style>
</head>
<body class="bg-gray-100">

    <div class="max-w-md mx-auto mt-8">

        <!-- Drag and drop list -->
        <div class="p-4 bg-white rounded-lg shadow-lg">
            <ul id="list" class="list-none p-0 m-0 bg-gray-100 border border-gray-300 min-h-40">
                <li id="item1" draggable="true" class="bg-white border border-gray-300 p-4 mb-2 cursor-move">Item 1</li>
                <li id="item2" draggable="true" class="bg-white border border-gray-300 p-4 mb-2 cursor-move">Item 2</li>
                <li id="item3" draggable="true" class="bg-white border border-gray-300 p-4 mb-2 cursor-move">Item 3</li>
                <li id="item4" draggable="true" class="bg-white border border-gray-300 p-4 mb-2 cursor-move">Item 4</li>
                <li id="item5" draggable="true" class="bg-white border border-gray-300 p-4 mb-2 cursor-move">Item 5</li>
            </ul>
        </div>

        <!-- Drop target -->
        <div id="target" class="mt-4 p-4 bg-white rounded-lg shadow-lg border-dashed border-2 border-gray-300 min-h-60">
            <p class="text-center text-gray-400">Drop items here</p>
        </div>

    </div>
    <script src="index.js"></script>
</body>
</html>

Enter fullscreen mode Exit fullscreen mode

Now create index.js and add this to index.html

JavaScript:-
Now write some JS for our drag and drop interface.

const listItems = document.querySelectorAll("#list li");
const target = document.querySelector("#target");

for (const listItem of listItems) {
    listItem.addEventListener("dragstart", dragStart);
}

target.addEventListener("dragover", dragOver);
target.addEventListener("drop", drop);

function dragStart(event) {
    event.dataTransfer.setData("text/plain", event.target.id);
}

function dragOver(event) {
    event.preventDefault();
    target.classList.add("border-gray-500");
}

function drop(event) {
    event.preventDefault();
    const itemId = event.dataTransfer.getData("text/plain");
    const item = document.getElementById(itemId);
    target.appendChild(item);
    target.classList.remove("border-gray-500");
}
Enter fullscreen mode Exit fullscreen mode

Code Explanation:-
First, it selects all the list items on the page and the target element using document.querySelectorAll and document.querySelector. This is done using CSS selectors: #list li selects all the li elements inside the element with the ID list, and #target selects the element with the ID target.

Next, it adds a dragstart event listener to each list item using a for...of loop. This event listener is triggered when the user starts dragging an item.

The dragStart function is called when the event is triggered. It sets the data that is being dragged by calling event.dataTransfer.setData("text/plain", event.target.id). The first argument specifies the data type (text/plain in this case), and the second argument is the ID of the element being dragged.

The code then adds a dragover event listener to the target element. This event listener is triggered when the user drags an item over the target element.

The dragOver function is called when the event is triggered. It calls event.preventDefault() to allow the drop event to be triggered. It also adds a CSS class to the target element to indicate that it can be dropped onto.

Finally, the code adds a drop event listener to the target element. This event listener is triggered when the user drops an item onto the target element.

The drop function is called when the event is triggered. It calls event.preventDefault() to prevent the default behavior (which is to navigate to a new page). It then gets the ID of the element being dragged by calling event.dataTransfer.getData("text/plain"). It retrieves the element by its ID using document.getElementById(itemId), and appends it to the target element using target.appendChild(item). Finally, it removes the CSS class that was added to the target element in the dragOver function.

Finally the Drag and Drop Interface is ready.

I hope you loved this.

Let's connect:

Github
Twitter
LinkedIn

Top comments (21)

Collapse
 
chasm profile image
Charles F. Munat

Nice. An excellent and clear explanation, sadly somewhat diminished by the inclusion of the irrelevant Tailwind dependency, as if we can do vanilla JS, but not vanilla CSS. Ironic.

Note: your JS is improperly formatted and initially I thought that lines 2-26 were inside a function. Took me a moment. Maybe remove the indent?

Definitely one of the clearest and most useful posts I've seen here in a while.

Collapse
 
devrohit0 profile image
Rohit Sharma

Thanks Charles for your feedback and pointing out the formatting issue ,it's been fixed now.
And for not using Vanilla CSS, I'll say, for a long time I'm not using vanilla CSS instead of that I'm using Tailwind CSS but from the next time I'll definitely use vanilla CSS with vanilla JS.

Collapse
 
chasm profile image
Charles F. Munat

Cool. I'm using Astro and TypeScript to generate vanilla JS/CSS/HTML -- no browser-side dependencies at all, but I still get types and components.

Collapse
 
kalpitj86 profile image
Kalpit Jain

Very well explained rohit 👍👍

Collapse
 
devrohit0 profile image
Rohit Sharma

Thanks Kalpit..

Collapse
 
dprincecoder profile image
Dprincecoder

Great code and explanation

Collapse
 
devrohit0 profile image
Rohit Sharma

Thanks Dprincecoder

Collapse
 
michael_osas profile image
Michael Osas

Very nice post👍🏼
I remember struggling with this feature on an image processing app some months ago.

Collapse
 
devrohit0 profile image
Rohit Sharma

Thanks Michael

Collapse
 
amircahyadi profile image
Amir-cahyadi

Nice sir 👍

Collapse
 
devrohit0 profile image
Rohit Sharma

Thanks Amir

Collapse
 
vulcanwm profile image
Medea

well explained, but does this not work on mobile?

Collapse
 
devrohit0 profile image
Rohit Sharma

Well, this is working on my mobile.
You just need to long press on the draggable then you'll be able to drag it.
Try this way, Hope it will work.

Collapse
 
vulcanwm profile image
Medea

Ah it does, this is great!

Thread Thread
 
devrohit0 profile image
Rohit Sharma

Thanks Medea

Collapse
 
ralphsunny114 profile image
Ugo Sunday Raphael • Edited

Good work. But right inside the Dropbox, can the text in each box be edited? I'm looking at a scenario where the boxes are list of products, then, after drag n drop, users can edit each quantity of product, to get a new combo. Please, I'll need your help or advice on this, if you understand it. Thanks.

Collapse
 
Sloan, the sloth mascot
Comment deleted
Collapse
 
codeofrelevancy profile image
Code of Relevancy

Thank you for this article..

Collapse
 
mizouzie profile image
Sam

Cool little feature and very nicely explained. I hope to use something based on this one day! Thanks!

Collapse
 
devrohit0 profile image
Rohit Sharma

Thank you for your kind words! I'm glad you found the feature and explanation helpful.

Collapse
 
louiecodes profile image
L O U I S

Great explanation, I'll try it out!