The HTML Drag and Drop API lets visitors grab an element with a pointer and drop it onto a target container—ideal for Kanban boards, file upload drop zones, and sortable lists. You enable dragging with a single HTML attribute (draggable="true") and wire the transfer using JavaScript events.
Three events drive a standard drag-and-drop workflow:
dragstart: Fires when dragging begins. Store the dragged element's ID inside event.dataTransfer.setData('text/plain', id).dragover: Fires continuously while hovering over a drop zone. You must call event.preventDefault() inside dragover, because browsers block dropping by default.drop: Fires when the user releases the mouse over the target. Read the ID via event.dataTransfer.getData('text/plain') and append or process the item.<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>HTML Drag and Drop Demo</title>
<style>
.board { display: flex; gap: 16px; font-family: system-ui, sans-serif; }
.zone { width: 180px; min-height: 110px; padding: 12px; border: 2px dashed #94a3b8; border-radius: 8px; }
.task { padding: 10px; background: #2563eb; color: #fff; border-radius: 6px; cursor: grab; }
</style>
</head>
<body>
<div class="board">
<div class="zone" id="todo">
<div id="task-1" class="task" draggable="true">Write HTML Tests</div>
</div>
<div class="zone" id="done">Drop here for Done</div>
</div>
<script>
const task = document.getElementById('task-1');
const zones = document.querySelectorAll('.zone');
task.addEventListener('dragstart', (e) => {
e.dataTransfer.setData('text/plain', e.target.id);
});
zones.forEach((zone) => {
zone.addEventListener('dragover', (e) => e.preventDefault());
zone.addEventListener('drop', (e) => {
e.preventDefault();
const id = e.dataTransfer.getData('text/plain');
const dragged = document.getElementById(id);
if (dragged) zone.appendChild(dragged);
});
});
</script>
</body>
</html>
e.preventDefault() in dragover: Without that single line, the drop event will never fire on the target box.input fallback.e.preventDefault() inside drop: In Firefox, skipping preventDefault() on drop can cause the browser to treat dragged text as a URL redirect.Text selections, img elements, and links (a with href) are draggable by default; any other element needs draggable="true".
Read event.dataTransfer.files inside the drop event listener after calling event.preventDefault() on both dragover and drop.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With
Experiment with the code from this lesson in our interactive playground.