How to Use the Drag and Drop API: Create Interactive User Experiences
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:
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
:
1 | <div draggable="true"> |
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:
1 | const element = document.querySelector('#my-drop-target'); |
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:
1 | 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:
- The
dragenter
event is fired on the drop target. - 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:
1 | element.addEventListener('dragenter', event => { |
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 eitherfile
orstring
.type
: Represents the MIME type of the item.
It also has two methods:
getAsFile()
: Returns aFile
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:
1 | element.addEventListener('dragenter', event => { |
The second method passes the item as a string to a callback function:
1 | element.addEventListener('dragenter', event => { |
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.