Learn how to utilize the Drag and Drop API to create interactive experiences for your users.

With the Drag and Drop API, you can define which elements on a page are draggable and intercept the user’s drag actions.

The API is well-supported on modern browsers:

Browser support

Before we dive into studying the API, it’s important to understand how to define which elements are draggable on a page. This can be done by adding the draggable attribute to the HTML of the element, with a value of true:

<div draggable="true">
 ...
</div>

By adding this attribute, you make the element draggable.

Tip: Images, text selections, and links are draggable by default unless you set draggable to false.

You can also enable dragging files from the user’s computer into the browser, which triggers a file transfer.

Determining where elements can be dragged to is another important aspect. Similar to how not all elements can be dragged, not all elements can also be drop targets. To make an element a drop target, you listen for its dragover event and either return false from it or call preventDefault() on the event:

const element = document.querySelector('#my-drop-target');
element.addEventListener('dragover', event => {
 event.preventDefault();
});

Once you have a draggable element and a drop target, you are ready to start. The events that you can interact with for the draggable element are:

  • dragstart
  • drag
  • dragend

For the drop target, the events are:

  • dragenter
  • dragover
  • dragleave
  • drop

Here is an overview of a drag and drop operation and the events fired:

When the user starts dragging a draggable element by clicking on it with the mouse and moving the mouse, or tapping and keeping the tap while moving the selection, the dragstart event is fired:

element.addEventListener('dragstart', event => {
 //...
});

The event object passed as a parameter to the event handling function is a DragEvent object. It extends from the more general Event object, which is shared with all other events like mouse, keyboard, and scrolling.

At this point, the element is being dragged, and the drag event is fired multiple times as the item is dragged. Throttling should be used, similar to scroll or mouseover events.

As soon as the draggable element enters a drop target:

  1. The dragenter event is fired on the drop target.
  2. The dragover event is fired on the drop target.

If a dragged element first enters a drop target and then moves away from it, the dragleave event is fired on the drop target.

If the user releases the mouse, the dragend event is fired on the dragged element, and a drop event is fired on the drop target.

Dragging Data: DataTransfer

Every drag and drop event comes with a DragEvent object, which includes a property called dataTransfer. This property holds the data being dragged and provides five properties:

  • dropEffect
  • effectAllowed
  • files
  • items (read-only)
  • types (read-only)

During the drag event, a few operations can be performed.

Setting/Getting the Effect

You can set the desired effect of the drag operation by setting the effectAllowed property in the dragstart event. The options available determine how the drop target should handle the dropped element:

  • none: It shouldn’t be dropped.
  • move: It can be moved.
  • copy: It can be copied.
  • link: It can be linked.
  • copyMove: It can be copied or moved.
  • copyLink: It can be copied or linked.
  • linkMove: It can be moved or linked.
  • all: It can be copied, moved, or linked.

These options are all strings, and the default is all.

The dropEffect property is used to get the type of the drag and drop operation, which can be set by the user through the use of modifier keys. For example, on a Mac, pressing the Alt key sets the drop target to copy the item instead of moving it.

This property is not read-only. We can edit it in a dragenter or dragover event, setting it to one of the string values mentioned above:

element.addEventListener('dragenter', event => {
 event.dataTransfer.dropEffect = 'move';
});

Dragged Data

You can access the items being transferred from the dataTransfer.items property, an array-like object that you can iterate using a loop. Each item is a DataTransferItem object.

A DataTransferItem has two read-only properties:

  • kind: Indicates the kind of the item being dragged. It returns a string with either file or string.
  • type: Represents the MIME type of the item.

It also has two methods:

  • getAsFile(): Returns a File object representing the dragged data.
  • getAsString(): Executes the callback function with a string object representing the dragged data.

Although their names are similar, these methods work differently. The first method returns a File object:

element.addEventListener('dragenter', event => {
 for (item of event.dataTransfer.items) {
 const theFile = item.getAsFile();
 }
});

The second method passes the item as a string to a callback function:

element.addEventListener('dragenter', event => {
 for (item of event.dataTransfer.items) {
 item.getAsString(theString => {
 console.log(theString);
 });
 }
});

The types of files being dragged are stored in the types property of the dataTransfer object. By default, the types property contains the string string. If a file is being dragged, the corresponding type is the string Files.

If there are files being transferred, they are also listed in the files property of dataTransfer, which points to a FileList object.