HTML5 Drag and Drop API

HTML5 introduced the Drag and Drop API which allows users to manipulate pages using drag and drop actions.

Identifying what is draggable in HTML

To make an element draggable it must have the draggable='true' attribute added:

   <div class="dragme" draggable='true'></div>

Note this does not work as a boolean attribute - using the shortcut <div class="dragme" draggable> would not work. When not set the default value of auto will use the browser’s defaults, which will allow text selections, images and links to be dragged.

The ondragstart event handler

As well as the draggable attribute you must also set up an event handler for the dragstart event, using either the ondragstart attribute or adding an event listener for the drag event:

   <div class="dragme1" draggable="true" ondragstart="console.log('Starting drag...')"></div>
   <div class="dragme2" draggable="true"></div>
   <script>
      function onDragStart() {
         console.log('Starting drag...');
      }
      const target = document.querySelector('.dragme2');
      target.addEventListener('dragstart', onDragStart);
   </script>

The event handler can set the dataTransfer property that can set the data type and contents of the dragged data, for instance:

   e.dataTransfer.setData("text/plain", "This is the data");

to store a string in the drag data.

The drag image

The dataTransfer object also allows you to set an image to use instead of the default translucent image generated from the drag target:

   e.dataTransfer.setDragImage(img, 10, 10);

The drag effect

When dragging an object you can trigger different types of operations on drop. The dataTransfer.effectAllowed attribute determines this and can be set to values such as copy to indicate the object will be copied, move to indicate the object will be moved to the target or link to indicate a connection will be made between the target and source.

The dragenter and dragover events

Up to this point, we have only been concerned with allowing an element to be dragged, however, the default handling for most targets on a page is to not allow a drop, giving you no targets to drag your source to. In order to allow a drop, you must prevent this default handling of drag events, either by returning false from either the ondragover or ondragenter

   <div class="target1" ondragover="return false"></div>
   <div class="target2"></div>
   <script>
      function onDragEnter(e) {
         e.preventDefault;
      }
      const target = document.querySelector('.target2');
      target.addEventListener('dragenter', onDragEnter);
   </script>

The Drop event

When the user releases the mouse the drag operation ends, and if dropped on a valid drop target (where the dragenter or dragover events cancel the default behaviour) the drop event will fire at the drop target.

Note if the drop is not over a valid target the drop event will not be fired and the drag operation is cancelled.

The drop event holds the data that was set by dataTransfer.setData, and the getData method can now be used to retrieve that data, with a key of the data type to retrieve:

   function handleDrop(e) {
     const data = e.dataTransfer.getData("text/plain");
     e.target.textContent = data;
     e.preventDefault();
}

The dragend event

Finally, the dragend event is fired at the source of the drag operation. This will be triggered whether the drag was a success or if it was cancelled. If cancelled, the e.dataTransfer.dropEffect property will be set to none. The dragend event handling can be used to perform any cleanup required on the source element.

Examples

Moving an image between boxes

The following CodePen is a simple demonstration of dragging an image between different boxes:

See the Pen Drag and Drop by Neil Lupton (@Neil188) on CodePen.

Using dataTransfer.getData to transfer data

The following CodePen is a mock character set up for a game, which allows you to choose a character class by dragging your choice up the main character panel.

See the Pen Drag And Drop Characters by Neil Lupton (@Neil188) on CodePen.

Written on June 9, 2018