Drag & Drop Elements with Vanilla JavaScript and HTML

Jess Mitchell

There are lots of great JavaScript libraries for adding a drag and drop feature to your app. What you may not know is that HTML has a native API built-in for making elements in the DOM draggable and droppable. Here we’ll look at creating a drag and drop feature using the HTML Drag and Drop API with a little vanilla JavaScript to set up the event handlers.

Overview

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 just a few event handlers, you can turn any element into a draggable item or a dropzone.

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

Here we’ll focus on the basics of building your drag and drop JavaScript functions to update the DOM directly.

Making HTML Elements Draggable

Let’s first start with what we want to drag. Let’s say we have a container with two types of child elements: children that can be dropped and children that can have elements dropped in them. For example, if we had a to-do list, we could drag our to-do items to the “done” area. (We’ll come back to this to-do list example at the end.)

To keep things simple, let’s refer to the items being moved as the draggable elements and the target as the “dropzone”.

<div class='parent'>
  <span id='draggableSpan'>
    draggable
  </span>
  <span> dropzone </span>
</div>
draggable
dropzone

Our first example here is the default and the children are not draggable.

So, let’s start by explicitly making our draggable element actually draggable. To do that we need to use the draggable attribute like so:

<div class='parent'>
  <span id='draggableSpan' draggable='true'>
    draggable
  </span>
  <span> dropzone </span>
</div>
draggable dropzone

Now if you try to move the draggable element with your mouse (sorry mobile visitors! 🙈) you should see a lighter version of the element move with your cursor on drag.

Without setting this draggable attribute to true, the default value is auto. This means whether the element is draggable will be determined by your browser’s default setting. Links (<a>), for example, are typically draggable by default. spans, however, are not.


Creating Drag and Drop Event Handlers

Currently, if we release the mouse while dragging the draggable element, nothing happens. Not super helpful! To actually trigger an action on drag or drop, we’ll need to utilize the Drag and Drop API for a minimum of three events:

  • ondragstart: Set the ID of the element being dragged and make any other changes we want to apply in the drag state.
  • ondragover: Browsers by default don’t trigger actions when a draggable element is dropped. We need to intervene here and let the drop actions happen!
  • ondrop: Whatever is supposed to happen on drop will be triggered here. Often the element getting dragged will move to a new parent element in the DOM.

The ondragstart, ondragover, ondrop event handlers are just the start. There are actually eight in total: ondrag, ondragend, ondragenter, ondragexit, ondragleave, ondragover, ondragstart, and ondrop. 💪

The DataTransfer Interface

The DataTransfer Interface 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 our DOM event.

The DataTransfer Interface (or object) can technically track information for multiple elements being dragged at the same time. For our example, we'll focus on dragging just one element. ✨

Updating Our Element on Drag

In this next step, we’ll set up our function ondragstart.

In our ondragstart function we can make whatever changes we’d like to see once the dragging has started. You can update the CSS of the element being dragged, make the dragged version a temporary image, and anything else you can think of that can be accessed through the DOM event.

The dataTransfer object’s property setData 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 and the actual data being transferred.

Our goal is to move our draggable element to a new parent, so 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 property so it can be used later like so:

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

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:

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. So, if you change anything when it starts dragging, the dragged element will keep that new styling unless you change it back. 🌈

Now that we have our JavaScript function for when dragging starts, we can pass it to our draggable item’s ondragstart attribute:

<div class='parent'>
  <span id='draggableSpan'
    draggable='true'
    ondragstart='onDragStart(event);'>
      draggable
  </span>

  <span> dropzone </span>
</div>

Here’s what dragging will look like in case you don’t have a mouse to try it yourself.

Element getting dragged with no dropzone

If you try to drag your item now, the styling declared in ondragstart will get applied but nothing will happen on drop. Let’s move on to our dropzone event handlers.


Allowing Droppable Elements

After ondragstart, our next function to set up is ondragover. As mentioned, drop actions get prevented by the browser by default so we need to prevent the browser from preventing our drop action. Two prevents equal an allow, right? 🚀

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

All we have to do here is stop the browser from interfering with our drop action. We can add this to our dropzone now so it can be a welcoming parent for any draggable elements.

<div class='parent'>
  <span id='draggableSpan'
    draggable='true'
    ondragstart='onDragStart(event);'>
      draggable
  </span>

  <span ondragover='onDragOver(event);'>
    dropzone
  </span>
</div>

Even though our dropzone can now accept draggable items, we still haven’t said what should actually happen when the mouse is released.

What To Do On Drop

Now we can introduce our third and final function: ondrop.

Our steps for this function will be as follows:

  • Remember the data we set with setData? Now we need to get that data with the dataTransfer object’s getData property. The data we set was the ID, so that’s what will be returned to us.
  • Select our draggable element with the ID we retrieved in step one.
  • Select our dropzone element.
  • Append our draggable element to the dropzone.
  • Reset our dataTransfer object.
function onDrop(event) {
  const id = event
    .dataTransfer
    .getData('text');

  const draggableElement = document.getElementById(id);
  const dropzone = event.target;
  
  dropzone.appendChild(draggableElement);

  event
    .dataTransfer
    .clearData();
}

Since this is our third and final function to build, we just need to pass it to the dropzone’s ondrop attribute. Once that’s done, we have a completed drag and drop feature!

<div class='parent'>
  <span id='draggableSpan'
    draggable='true'
    ondragstart='onDragStart(event);'>
      draggable
  </span>

  <span
    ondragover='onDragOver(event);'
    ondrop='onDrop(event);'>
      dropzone
  </span>
</div>
Element getting dropped in dropzone

Our example here is as basic as it gets to show how to make anything on your page draggable or droppable. You can have multiple draggable elements, multiple dropzones, and customize it a bunch with all the other Drag and Drop API event handlers.

Here’s one more example of how you could use this API: a simple to-do list as mentioned at the start. 🔥

Todo list drag and drop example

To replicate this, simply add more draggable elements exactly like we did above. Just make sure your IDs are always unique!


Further Reading

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

  Tweet It

🕵 Search Results

🔎 Searching...

Sponsored by #native_company# — Learn More
#native_title# #native_desc#
#native_cta#