Drag and drop is an essential feature that enhances user interaction and facilitates a seamless user experience. Whether you're looking to build a file uploader, a sortable list, or an interactive game, understanding how to harness the capabilities of this API is a crucial skill to have in your web development toolkit.
The Basics of Drag and Drop in HTML
In a typical drag-and-drop system, there are two types of elements: the first type comprises draggable elements that users can move with a mouse, and the second type includes droppable elements that typically specify where users can place an element.
To implement drag and drop, you have to tell the browser what elements you want to be draggable. To make an element draggable by the user, that element should have a draggable HTML attribute set to true, like this:
<div draggable="true">This element is draggable</div>
When the user starts firing a drag event, the browser supplies a default "ghost" image that typically provides feedback regarding an element being dragged.
You can customize this image by supplying your own image instead. To do this, select the draggable element from the DOM, create a new image to represent the custom feedback image, and add a dragstart drag event listener like this:
let img = new Image();
img.src = 'https://upload.wikimedia.org/wikipedia/commons/thumb/9/90/Twemoji_1f600.svg/220px-Twemoji_1f600.svg.png';
document.querySelector('div').addEventListener('dragstart', (event)=>{
event.dataTransfer.setDragImage(img, 10, 10);
})
In the code block above, the setDragImage method has three parameters. The first parameter references the image. The other parameters represent the horizontal and vertical offsets of the image respectively. When you run the code in the browser and start dragging an element, you will notice that the custom drag image has been replaced with the custom image set earlier.
If you want to allow a drop, you must prevent the default behavior by canceling both the dragenter and dragover events, like this:
const dropElement = document.querySelector("drop-target");
dropElement.addEventListener("dragenter", (ev) => {
ev.preventDefault();
});
dropElement.addEventListener("dragover", (ev) => {
ev.preventDefault();
});
Understanding the DragEvent Interface
JavaScript features a DragEvent interface that represents a drag-and-drop interaction from the user. Below is a list of possible event types under the DragEvent interface.
- drag: The user fires this event while dragging an element.
- dragend: This event fires when the drag operation ends or when the user interrupts it. A typical drag operation can end by releasing the mouse button or pressing the escape key.
- dragenter: A dragged element triggers this event when it enters a valid drop target.
- dragleave: When the dragged element leaves a drop target, this event fires.
- dragover: When the user drags a draggable element over a drop target, the event fires.
- dragstart: The event fires at the start of a drag operation.
- drop: The user triggers this event when they drop an element onto a drop target.
When dragging a file into the browser from an environment outside the browser (for example, the operating system file manager), the browser does not trigger the dragstart or dragend events.
DragEvent can come in handy if you want to dispatch a custom drag event programmatically. For example, if you want to a div to fire custom drag events on page load, here is how you do it. First, create a new custom DragEvent() like this:
const customDragStartEvent = new DragEvent('dragstart', {
dataTransfer: new DataTransfer(),
})
const customDragEndEvent = new DragEvent('dragend');
In the code block above, customDragStartEvent represents an instance of DragEvent(). In customDragStartEvent, there are two constructor arguments. The first represents the drag event type, which can be one of the seven event types mentioned earlier.
The second argument is an object with a dataTransfer key representing an instance of DataTransfer, which you will learn more about later in this guide. Next, grab the element you want to trigger the event from, from the Document Object Model (DOM).
const draggableElement = document.querySelector("#draggable");
Then add, the event listeners like this:
draggableElement.addEventListener('dragstart', (event) => {
console.log('Drag started!');
event.dataTransfer.setData('text/plain', 'Hello, world!');
});
draggableElement.addEventListener('dragend', () => {
console.log('Drag ended!');
});
In the first event listener above, the callback function feature logs the text, "Drag started!" and invokes the setData method on the dataTransfer property on the event object. Now, you can trigger the custom events like this:
draggableElement.dispatchEvent(customDragStartEvent);
draggableElement.dispatchEvent(customDragEndEvent);
Transferring Data With dataTransfer
The dataTransfer object serves as a bridge between the source element (the draggable item) and the target element (the droppable area) during a drag-and-drop operation. It acts as a temporary storage container for data that you want to share between these elements.
This data can take various forms, such as text, URLs, or custom data types, making it a versatile tool for implementing a wide range of drag-and-drop functionality.
Using setData() to Package Data
To transfer data from a draggable element to a droppable one, you'll use the setData() method provided by the dataTransfer object. This method allows you to package the data you want to transfer and specify the data type. Here's a basic example:
element.addEventListener('dragstart', (event) => {
event.dataTransfer.setData('text/plain', 'Hello, world!');
});
When a user starts dragging the specified element, setData() packages the text "Hello, world!" with the data type text/plain. This data is now associated with the drag event and can be accessed by the droppable target during the drop operation.
Retrieving Data With getData()
On the receiving end, within a droppable element's event listener, you can retrieve the transferred data using the getData() method:
element.addEventListener('drop', (event) => {
const transferredData = event.dataTransfer.getData('text/plain');
console.log(`Received data: ${transferredData}`);
});
The code block above retrieves the data with the same data type (text/plain) that was set using the setData() method earlier. This allows you to access and manipulate the transferred data as needed within the droppable element's context.
Use Cases for Drag and Drop Interfaces
Integrating drag-and-drop functionality into your web applications can be a powerful enhancement, but it's essential to understand when and why you should implement it.
- File Uploaders: Allowing users to drag files directly from their desktop or file manager to a designated drop area simplifies the upload process.
- Sortable Lists: If your application involves lists of items, such as task lists, playlists, or image galleries, users might appreciate the ability to reorder items via drag and drop.
- Interactive Dashboards: For data visualization and reporting tools, drag and drop can be a powerful way for users to customize their dashboards by rearranging widgets and charts.
Keeping Accessibility in Mind
While drag and drop can be visually appealing and enhance user experience, it's crucial to ensure that your implementation remains accessible to all users, including those with disabilities. Provide alternative methods for interaction, such as keyboard controls, to make your application inclusive.