Drag and drop is a familiar user interface concept where you "grab" an object and move it to a new location. With the HTML Drag and Drop API, you can implement this feature natively in the browser.
Modern browsers provide excellent support for this API:
| API | Chrome | Edge | Firefox | Safari | Opera |
|---|---|---|---|---|---|
| Drag & Drop | 4.0+ | 9.0+ | 9.0+ | 6.0+ | 12.0+ |
Building a drag-and-drop interaction involves three main steps: making an object moveable, defining the data to move, and setting a valid drop zone.
By default, most HTML elements are not draggable. You must add the draggable="true" attribute.
<img id="myImage" src="logo.png" draggable="true">
<p id="textBlock" draggable="true"> You can move this text! <p>
When the user starts dragging, you need to store the ID of the element so the browser knows what is being moved. We use the dataTransfer.setData() method for this.
function startDragging(event) {
// Store the ID of the element being dragged
event.dataTransfer.setData("textID", event.target.id);
}
Browsers naturally prevent dropping data into other elements. To allow a drop, we must cancel the default behavior using preventDefault().
function allowDrop(event) {
event.preventDefault(); // This allows the drop to happen
}
When the user releases the mouse, we retrieve the stored ID and move the element to the new container.
function handleDrop(event) {
event.preventDefault();
// Retrieve the ID we stored earlier
const elementID = event.dataTransfer.getData("textID");
// Move the element into the new container
event.target.appendChild(document.getElementById(elementID));
}
Copy and paste this code to see a functional drag-and-drop demo.
<!DOCTYPE html>
<html>
<head>
<style>
.drop-box {
width: 350px;
height: 100px;
padding: 10px;
border: 2px dashed #ccc;
margin-bottom: 20px
}
</style>
<script>
function startDragging(ev) {
ev.dataTransfer.setData("elementID", ev.target.id);
}
function allowDrop(ev) {
ev.preventDefault();
}
function handleDrop(ev) {
ev.preventDefault();
const id = ev.dataTransfer.getData("elementID");
ev.target.appendChild(document.getElementById(id));
}
</script>
</head>
<body>
<h3> Drag the elements into the box: </h3>
<div class="drop-box" ondrop="handleDrop(event)" ondragover="allowDrop(event)"> <div>
<img id="dragImg" src="https://via.placeholder.com/150/0000FF/808080?Text=DragMe"
draggable="true" ondragstart="startDragging(event)" width="100">
<h2> Move this Heading! <h2>
</body>
</html>
Draggable: Set draggable="true" on the source
Data Storage: Use event.dataTransfer.setData() inside the ondragstart event.
Enable Drop: Call event.preventDefault() inside the ondragover event.
Finalize: Use event.target.appendChild() inside the ondrop event to complete the move.