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 notdraggable.
So, let’s start by explicitly making our draggable element actually draggable. To do that we need to use the draggableattribute like so:
<div class='parent'>
  <span id='draggableSpan' draggable='true'>
    draggable
  </span>
  <span> dropzone </span>
</div>
draggabledropzone
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 ondragstartattribute:
<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.