HTML Drag and Drop
HTML5 Drag and Drop is a built-in browser feature that lets users click and drag elements from one place and drop them in another. No external libraries required — just HTML attributes and JavaScript event handlers. Kanban boards, file uploaders, and reorderable lists all use this feature.
How Drag and Drop Works
Visual Diagram — The Basic Flow
1. User presses mouse button on a draggable element
[📦 Item A] ← draggable element
2. User holds and moves the mouse
[📦 Item A] ←──── drag
3. User releases mouse over a drop zone
+------------------+
| Drop Zone | ← drop target
| [📦 Item A] |
+------------------+
4. JavaScript handles what happens next
(move, copy, sort, upload, etc.)
Making an Element Draggable
Add the draggable="true" attribute to any HTML element to make it draggable. Without this attribute, only images and links are draggable by default.
<div draggable="true">Drag me!</div> <p draggable="true">This paragraph is draggable</p> <img src="photo.jpg" alt="Photo"> <!-- images draggable by default -->
Drag and Drop Events
The browser fires a series of events as the drag action progresses. You listen for these events on the draggable element and on the drop target.
Events on the Draggable Element
Event When It Fires ----------- ------------------------------------------- dragstart User starts dragging (mouse button held, drag begins) drag Fires continuously while user is dragging dragend User releases mouse — drag is complete
Events on the Drop Target
Event When It Fires ----------- ------------------------------------------- dragenter Dragged item enters the drop target area dragover Dragged item moves over the drop target (fires repeatedly) dragleave Dragged item leaves the drop target area drop User releases mouse over the drop target
Basic Drag and Drop Example
This example drags a box into a drop zone.
<div id="dragBox"
draggable="true"
ondragstart="handleDragStart(event)"
style="padding:12px; background:#4a90d9; color:white; display:inline-block; cursor:grab;">
Drag Me
</div>
<div id="dropZone"
ondragover="handleDragOver(event)"
ondrop="handleDrop(event)"
style="width:200px; height:100px; border:2px dashed #888; margin-top:20px; padding:10px;">
Drop Here
</div>
<script>
function handleDragStart(event) {
// Store the id of the element being dragged
event.dataTransfer.setData("text/plain", event.target.id);
}
function handleDragOver(event) {
// REQUIRED: prevent default to allow drop
event.preventDefault();
}
function handleDrop(event) {
event.preventDefault();
const id = event.dataTransfer.getData("text/plain");
const draggedElement = document.getElementById(id);
event.target.appendChild(draggedElement);
}
</script>
Why preventDefault() Is Required
By default, browsers do not allow dropping on elements. Calling event.preventDefault() inside dragover says: "Yes, this element accepts a drop." Without it, the drop event never fires.
The dataTransfer Object
The dataTransfer object carries data between the drag source and the drop target. You write data in dragstart and read it in drop.
// Writing data during dragstart:
event.dataTransfer.setData("text/plain", "Hello");
event.dataTransfer.setData("text/html", "<b>Hello</b>");
// Reading data during drop:
const text = event.dataTransfer.getData("text/plain");
const html = event.dataTransfer.getData("text/html");
Common MIME Types for dataTransfer
"text/plain" → plain text (most common) "text/html" → HTML content "text/uri-list" → one or more URLs "application/json" → JSON data string
Visual Feedback During Drag
Changing the appearance of the drop zone when something is dragged over it gives users clear feedback.
<style>
.drop-zone { border: 2px dashed #aaa; padding: 20px; }
.drop-zone.drag-over { background-color: #e8f4e8; border-color: green; }
</style>
<script>
const dropZone = document.getElementById("dropZone");
dropZone.addEventListener("dragenter", function() {
dropZone.classList.add("drag-over");
});
dropZone.addEventListener("dragleave", function() {
dropZone.classList.remove("drag-over");
});
dropZone.addEventListener("drop", function(event) {
event.preventDefault();
dropZone.classList.remove("drag-over");
// handle the drop
});
</script>
The dropEffect and effectAllowed
These properties control the cursor icon shown during dragging and what type of operation is allowed.
// Set in dragstart — what operations the source allows: event.dataTransfer.effectAllowed = "move"; // only move event.dataTransfer.effectAllowed = "copy"; // only copy event.dataTransfer.effectAllowed = "all"; // move, copy, or link // Set in dragover — what operation the target will perform: event.dataTransfer.dropEffect = "move"; // shows move cursor event.dataTransfer.dropEffect = "copy"; // shows copy (plus) cursor
Dragging Files from the Desktop
Users can drag files from their file manager and drop them into a browser drop zone. The dropped files are available through event.dataTransfer.files.
<div id="fileDropZone"
ondragover="event.preventDefault()"
ondrop="handleFileDrop(event)"
style="border:2px dashed #888; padding:30px; text-align:center;">
Drag files here to upload
</div>
<p id="fileInfo"></p>
<script>
function handleFileDrop(event) {
event.preventDefault();
const files = event.dataTransfer.files;
let info = "";
for (let i = 0; i < files.length; i++) {
info += files[i].name + " (" + files[i].size + " bytes)\n";
}
document.getElementById("fileInfo").textContent = info;
}
</script>
Visual Diagram — File Drop Zone
Desktop file manager: 📄 report.pdf 📸 photo.jpg User drags photo.jpg into browser: +--------------------------------+ | Drag files here to upload | | | | [📸 photo.jpg] | ← visual feedback on hover +--------------------------------+ On drop, JavaScript reads: files[0].name = "photo.jpg" files[0].size = 204800 (bytes) files[0].type = "image/jpeg"
Sortable List with Drag and Drop
A common use case is reordering a list by dragging items.
<ul id="sortable">
<li draggable="true">Item 1</li>
<li draggable="true">Item 2</li>
<li draggable="true">Item 3</li>
</ul>
<script>
let draggedItem = null;
const list = document.getElementById("sortable");
list.addEventListener("dragstart", function(e) {
draggedItem = e.target;
e.target.style.opacity = "0.5";
});
list.addEventListener("dragend", function(e) {
e.target.style.opacity = "1";
});
list.addEventListener("dragover", function(e) {
e.preventDefault();
const target = e.target;
if (target && target !== draggedItem && target.nodeName === "LI") {
list.insertBefore(draggedItem, target);
}
});
</script>
Browser Support
HTML5 Drag and Drop works in all modern desktop browsers. Mobile browsers have limited or no support for native drag and drop — touch events work differently. For mobile-friendly drag and drop, JavaScript libraries like SortableJS or interact.js are commonly used alongside the native API.
Accessibility Note
Native drag and drop is not keyboard accessible. Users who navigate with a keyboard or switch device cannot use drag to reorder items. Always provide an alternative — like up/down buttons — for any functionality that relies on drag and drop.
