HTML Drag and Drop
With the Drag and Drop API, users can pick up an element with the mouse and drop it somewhere else on the page.
How Drag and Drop Works
Every drag has two sides:
- The draggable element, the thing the user picks up.
- The drop zone, the place where it can be dropped.
| Event | Fires on | When |
|---|---|---|
dragstart | The dragged element | The user starts dragging |
dragend | The dragged element | The drag finishes (dropped or cancelled) |
dragenter | The drop zone | The dragged item enters it |
dragover | The drop zone | Again and again while the item is over it |
dragleave | The drop zone | The item leaves it |
drop | The drop zone | The user lets go over it |
Step 1: Make an Element Draggable
Links and images can be dragged by default. For anything else, add draggable="true":
Example
<div id="card" draggable="true">Drag me</div>Step 2: Remember What Is Dragged
In dragstart, save the element's id in dataTransfer. This is the "luggage" that travels with the drag.
Example
card.addEventListener("dragstart", function (event) {
event.dataTransfer.setData("text/plain", event.target.id);
});Step 3: Allow Dropping
By default, elements refuse drops. You must call event.preventDefault() in the dragover event to say "dropping here is allowed".
Example
zone.addEventListener("dragover", function (event) {
event.preventDefault();
});Forgetting preventDefault() in dragover is the most common drag and drop mistake. Without it, the drop event never fires.
Step 4: Handle the Drop
Example
zone.addEventListener("drop", function (event) {
event.preventDefault();
const id = event.dataTransfer.getData("text/plain");
zone.appendChild(document.getElementById(id));
});appendChild moves the element into the drop zone.
A Complete Example
Drag the fruit into the basket.
Example
<!DOCTYPE html>
<html>
<head>
<style>
.item { display: inline-block; padding: 8px 14px; margin: 4px; background: #ffe7a3;
border-radius: 6px; cursor: grab; }
#basket { min-height: 80px; margin-top: 16px; padding: 10px; border: 3px dashed #999;
border-radius: 8px; }
#basket.over { border-color: #e34c26; background: #fff3f0; }
</style>
</head>
<body>
<div>
<span class="item" id="mango" draggable="true">Mango</span>
<span class="item" id="banana" draggable="true">Banana</span>
<span class="item" id="apple" draggable="true">Apple</span>
</div>
<div id="basket">Basket: drop fruit here</div>
<p id="msg"></p>
<script>
const basket = document.getElementById("basket");
document.querySelectorAll(".item").forEach(function (item) {
item.addEventListener("dragstart", function (event) {
event.dataTransfer.setData("text/plain", item.id);
});
});
basket.addEventListener("dragover", function (event) {
event.preventDefault();
basket.classList.add("over");
});
basket.addEventListener("dragleave", function () {
basket.classList.remove("over");
});
basket.addEventListener("drop", function (event) {
event.preventDefault();
basket.classList.remove("over");
const id = event.dataTransfer.getData("text/plain");
basket.appendChild(document.getElementById(id));
document.getElementById("msg").innerHTML = "You added " + id + " to the basket.";
});
</script>
</body>
</html>Try it Yourself »The over class colours the basket while something is above it, so the user can see where the drop will land.
A Simple Task Board
The same idea builds a "To do / Done" board, like the ones used to plan projects. Each column is a drop zone.
Example
<!DOCTYPE html>
<html>
<head>
<style>
.board { display: flex; gap: 12px; }
.col { flex: 1; min-height: 150px; padding: 8px; background: #f1f1f1; border-radius: 8px; }
.task { padding: 8px; margin: 6px 0; background: white; border: 1px solid #ccc;
border-radius: 6px; cursor: grab; }
</style>
</head>
<body>
<div class="board">
<div class="col" id="todo">
<h3>To do</h3>
<div class="task" id="t1" draggable="true">Write HTML page</div>
<div class="task" id="t2" draggable="true">Add CSS styles</div>
</div>
<div class="col" id="done">
<h3>Done</h3>
</div>
</div>
<script>
document.querySelectorAll(".task").forEach(function (task) {
task.addEventListener("dragstart", function (e) {
e.dataTransfer.setData("text/plain", task.id);
});
});
document.querySelectorAll(".col").forEach(function (col) {
col.addEventListener("dragover", function (e) { e.preventDefault(); });
col.addEventListener("drop", function (e) {
e.preventDefault();
col.appendChild(document.getElementById(e.dataTransfer.getData("text/plain")));
});
});
</script>
</body>
</html>Try it Yourself »Dropping Files from the Computer
A drop zone can also receive files dragged from the desktop. They arrive in event.dataTransfer.files:
Example
zone.addEventListener("drop", function (event) {
event.preventDefault();
const file = event.dataTransfer.files[0];
zone.innerHTML = "You dropped: " + file.name + " (" + file.size + " bytes)";
});Things to Keep in Mind
- The HTML Drag and Drop API works with a mouse. On most phones, touch dragging needs extra code or a library.
- Some users cannot use a mouse. Always give another way too, such as a button "Move to Done".
Exercise
Exercise
Your drop event never fires. What is the most likely reason?
