Tutorial

How To Create Drag and Drop Elements with Vanilla JavaScript and HTML

Updated on July 27, 2020
authorauthor

Jess Mitchell and Bradley Kouchi

English
How To Create Drag and Drop Elements with Vanilla JavaScript and HTML

Introduction

Dragging-and-dropping is a common user interaction that you can find in many graphical user interfaces.

There are pre-existing JavaScript libraries for adding a drag-and-drop feature to your app. However, there may be situations where a library is not available or introduces an overhead or dependency that your project does not need. In these situations, knowledge of the APIs available to you in modern web browsers can offer alternative solutions.

The HTML Drag and Drop API relies on the DOM’s event model to get information on what is being dragged or dropped and to update that element on drag or drop. With JavaScript event handlers, you can turn any element into a draggable item or an item that can be dropped into.

In this tutorial, we will build a drag-and-drop example using the HTML Drag and Drop API with vanilla JavaScript to use the event handlers.

Prerequisites

To complete this tutorial, you will need:

  • A modern web browser that supports the Drag and Drop API (Chrome 4+, Firefox 3.5+, Safari 3.1+, Edge 18+).

Step 1 — Creating the Project and Initial Markup

Our project will consist of a container with two types of child elements:

  • Child elements that can you can drag
  • Child elements that can have elements dropped into them

First, open your terminal window and create a new project directory:

  1. mkdir drag-and-drop-example

Next, navigate to that directory:

  1. cd drag-and-drop-example

Then, create an index.html file in that directory:

  1. nano index.html

Next, add boilerplate code for a HTML webpage:

index.html
<!DOCTYPE html>
<html>
  <head>
    <title>My Drag-and-Drop Example</title>
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
  </body>
</html>

And between the <body> tags add your draggable item and your dropzone (drop target):

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
  >
    dropzone
  </div>
</div>

Save and close the file. Then, create a style.css file:

  1. nano style.css

Next, add styles for the elements in our index.html file:

style.css
.example-parent {
  border: 2px solid #DFA612;
  color: black;
  display: flex;
  font-family: sans-serif;
  font-weight: bold;
}

.example-origin {
  flex-basis: 100%;
  flex-grow: 1;
  padding: 10px;
}

.example-draggable {
  background-color: #4AAE9B;
  font-weight: normal;
  margin-bottom: 10px;
  margin-top: 10px;
  padding: 10px;
}

.example-dropzone {
  background-color: #6DB65B;
  flex-basis: 100%;
  flex-grow: 1;
  padding: 10px;
}

This will add some formatting to the app. Now you can view index.html in the browser and observe that this produces a draggable <div> and a dropzone <div>.

Screenshot of draggable and dropzone divs

Next, we will explicitly make the first <div> draggable by adding the draggable attribute:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
  >
    dropzone
  </div>
</div>

Save and close the file.

Finally, view index.html in the browser again. If we click on the draggable <div> and drag it across the screen, there should be a visual indication of it moving.

The default value for the draggable attribute is auto. That means whether the element is draggable will be determined by your browser’s default behavior. Typically this means text selections, images, and links are draggable without specifying draggable="true".

You now have an HTML file with a draggable element. We will move on to adding onevent handlers.

Step 2 — Handling Drag-and-Drop Events with JavaScript

Currently, if we release the mouse while dragging the draggable element, nothing happens. To trigger an action on drag or drop on DOM elements, we’ll need to utilize the Drag and Drop API:

  • ondragstart: This event handler will be attached to our draggable element and fire when a dragstart event occurs.
  • ondragover: This event handler will be attached to our dropzone element and fire when a dragover event occurs.
  • ondrop: This event handler will also be attached to our dropzone element and fire when a drop event occurs.

Note: There are eight event handlers in total: ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart, and ondrop. For our example, we will not require them all.

First, let’s reference a new script.js file in our index.html:

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

Next, create a new script.js file:

  1. nano script.js

The DataTransfer object will keep track of the information related to the current drag happening. To update our element on drag and on drop, we need to directly access the DataTransfer object. To do this, we can select the dataTransfer property from the DOM element’s DragEvent.

Note: The DataTransfer object can technically track information for multiple elements being dragged at the same time. For our example, we’ll focus on dragging one element.

The dataTransfer object’s setData method can be used to set the drag state information for your currently dragged element. It takes two parameters:

  • a string that declares the format of the second parameter
  • the actual data being transferred

Our goal is to move our draggable element to a new parent element. We need to be able to select our draggable element with a unique id. We can set the id of the dragged element with the setData method so it can be used later.

Let’s revisit our script.js file and create a new function to use setData:

script.js
function onDragStart(event) {
  event
    .dataTransfer
    .setData('text/plain', event.target.id);
}

Note: Internet Explorer 9 through 11 reportedly has problems with using 'text/plain'. The format needs to 'text' for that browser.

To update the dragged item’s CSS styling, we can access its styles using the DOM event again and by setting whatever styles we want for the currentTarget.

Let’s add to our function and change the backgroundColor to yellow:

script.js
function onDragStart(event) {
  event
    .dataTransfer
    .setData('text/plain', event.target.id);

  event
    .currentTarget
    .style
    .backgroundColor = 'yellow';
}

Note: Any styles you change will need to be manually updated again on drop if you want drag-only styles. If you change anything when it starts dragging, the dragged element will keep that new styling unless you change it back.

Now, we have our JavaScript function for when dragging starts.

We can add ondragstart to the draggable element in index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div class="example-dropzone">
    dropzone
  </div>
</div>

View index.html in your browser. If you try to drag your item now, the styling declared in our function will get applied:

Animated gif depicting an element getting dragged but not dropping

However, nothing will happen when you release your click.

The next event handler fired in this sequence is ondragover.

The default drop behavior for certain DOM elements like <div>s in browsers typically does not accept dropping. This behavior will intercept the behavior we are attempting to implement. To ensure that we get the desired drop behavior, we will apply preventDefault.

Let’s revisit the script.js file and create a new function to use preventDefault. Add this code to the end of the file:

script.js
function onDragOver(event) {
  event.preventDefault();
}

Now, we can add ondragover to our dropzone element in index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
  >
    dropzone
  </div>
</div>

At this point, we still have not written code handle the actual dropping. The final event handler fired in this sequence is ondrop.

Let’s revisit our script.js file and create a new function.

We can reference the data we saved earlier with dataTransfer object’s setData method. We will use dataTransfer object’s getData method. The data we set was the id, so that’s what will be returned to us:

script.js
function onDrop(event) {
  const id = event
    .dataTransfer
    .getData('text');
}

Select our draggable element with the id we retrieved:

script.js
function onDrop(event) {
  // ...

  const draggableElement = document.getElementById(id);
}

Select our dropzone element:

script.js
function onDrop(event) {
  // ...

  const dropzone = event.target;
}

Append our draggable element to the dropzone:

script.js
function onDrop(event) {
  // ...

  dropzone.appendChild(draggableElement);
}

Reset our dataTransfer object:

script.js
function onDrop(event) {
  // ...

  event
    .dataTransfer
    .clearData();
}

Now, we can add ondrop to our dropzone element in index.html:

index.html
<div class="example-parent">
  <div class="example-origin">
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      draggable
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
    ondrop="onDrop(event);"
  >
    dropzone
  </div>
</div>

Once that’s done, we have a completed drag-and-drop feature. View index.html in your browser and drag the draggable element to the dropzone.

Animated gif depicting an element getting dragged and dropped into a drop target

Our example handles the scenario of a single draggable item and a single drop target. You can have multiple draggable items, multiple drop targets, and customize it with all the other Drag and Drop API event handlers.

Step 3 — Building an Advanced Example with Multiple Draggable Items

Here’s one more example of how you could use this API: a to-do list with draggable tasks that you can move from a "To-do" column to a "Done" column.

Animated gif depicting multiple To-do tasks being dragged and dropped into a Done column

To create your own to-do list, add more draggable elements with unique ids to index.html:

index.html
<div class="example-parent">
  <h1>To-do list</h1>
  <div class="example-origin">
    To-do
    <div
      id="draggable-1"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 1
    </div>
    <div
      id="draggable-2"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 2
    </div>
    <div
      id="draggable-3"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 3
    </div>
    <div
      id="draggable-4"
      class="example-draggable"
      draggable="true"
      ondragstart="onDragStart(event);"
    >
      thing 4
    </div>
  </div>

  <div
    class="example-dropzone"
    ondragover="onDragOver(event);"
    ondrop="onDrop(event);"
  >
    Done
  </div>
</div>

View index.html in your browser and drag the items in the To-do column to the Done column. You have created a to-do application and tested the functionality.

Conclusion

In this article, you created a to-do app to explore the drag-and-drop functionality that is available to modern web browsers.

The Drag and Drop API provides multiple options for customizing your actions beyond dragging and dropping. For example, you can update the CSS styling of your dragged items. Also, instead of moving the item, you can choose to copy your draggable item so that it gets replicated on drop.

Bear in mind that while many web browsers support this technology, you may not be able to rely on it if your audience consists of devices that do not support this functionality.

To learn more about all you can drop with the Drag and Drop API, check out MDN’s docs on it.

Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

Learn more about our products

About the authors
Default avatar
Jess Mitchell

author



Still looking for an answer?

Ask a questionSearch for more help

Was this helpful?
 
6 Comments


This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

It’s insane how easy this was! This was an extremely helpful guide

This comment has been deleted

    This is so cool! Thanks for sharing.

    Nicely explained. Although I can’t use it since this feature is not well supported on mobile browsers yet, I still learned a lot from it.

    And by just adding: ondragover=“onDragOver(event);” ondrop=“onDrop(event);” to the example-parent div, I can drag the draggables back into the starting box. Neat.

    Dear Jess Mitchell,

    I have some questions. Is it possible to talk with you?

    Hey! Great tutorial. I’ve used it in an app I’m working on but wondered if you could help me with one last thing. I’d like the dropped element to revert to it’s original colour once in the drop zone. How would I do this?

    Thanks

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Featured on Community

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more