HTML Drag and Drop
Learn how to create interactive drag and drop interfaces using the HTML Drag and Drop API
The HTML Drag and Drop API allows you to make elements draggable and create drop zones where users can drag and drop items. This creates intuitive, interactive user interfaces for tasks like file uploads, sortable lists, and kanban boards.
Drag and Drop Basics
To implement drag and drop, you need two things:
🎯 Key Components
-
Draggable Element: An element that can be
dragged (set
draggable="true"
) - Drop Target: An area where draggable elements can be dropped
Making Elements Draggable
To make an element draggable, add the
draggable="true"
attribute:
Basic Draggable Element
<div id="drag1" draggable="true" ondragstart="drag(event)">
Drag me!
</div>
<script>
function drag(event) {
// Store the id of the dragged element
event.dataTransfer.setData("text", event.target.id);
}
</script>
Note
Images and links are draggable by default in most browsers.
Other elements need draggable="true"
.
Creating a Drop Zone
To create a drop zone, you need to handle the
ondragover
and ondrop
events:
Drop Zone Example
<div id="dropzone"
ondrop="drop(event)"
ondragover="allowDrop(event)"
style="width:200px; height:200px; border:1px solid black;">
Drop here
</div>
<script>
function allowDrop(event) {
// Prevent default to allow drop
event.preventDefault();
}
function drop(event) {
event.preventDefault();
// Get the id of the dragged element
var data = event.dataTransfer.getData("text");
// Append the dragged element to the drop zone
event.target.appendChild(document.getElementById(data));
}
</script>
Drag and Drop Events
The Drag and Drop API provides several events that fire during the drag operation:
⚠️ Important
You must call event.preventDefault()
in the
dragover
event handler to allow dropping. By
default, dropping is not allowed.
The DataTransfer Object
The dataTransfer
object is used to hold data being
dragged:
Complete Drag and Drop Example
Full Working Example
<style>
.draggable {
width: 100px;
height: 100px;
background: #4CAF50;
color: white;
padding: 20px;
text-align: center;
cursor: move;
margin: 10px;
border-radius: 5px;
}
.dropzone {
width: 300px;
height: 300px;
border: 3px dashed #ccc;
padding: 10px;
margin: 10px;
min-height: 100px;
background: #f9f9f9;
}
.dropzone.dragover {
background: #e3f2fd;
border-color: #2196F3;
}
</style>
<div class="draggable" draggable="true" ondragstart="dragStart(event)" id="item1">
Item 1
</div>
<div class="draggable" draggable="true" ondragstart="dragStart(event)" id="item2">
Item 2
</div>
<div class="dropzone"
ondrop="drop(event)"
ondragover="dragOver(event)"
ondragenter="dragEnter(event)"
ondragleave="dragLeave(event)">
Drop Zone
</div>
<script>
function dragStart(event) {
// Store the id of dragged element
event.dataTransfer.setData("text/plain", event.target.id);
event.dataTransfer.effectAllowed = "move";
}
function dragOver(event) {
// Prevent default to allow drop
event.preventDefault();
event.dataTransfer.dropEffect = "move";
}
function dragEnter(event) {
// Add visual feedback
if (event.target.className === "dropzone") {
event.target.classList.add("dragover");
}
}
function dragLeave(event) {
// Remove visual feedback
if (event.target.className.includes("dropzone")) {
event.target.classList.remove("dragover");
}
}
function drop(event) {
event.preventDefault();
// Remove visual feedback
event.target.classList.remove("dragover");
// Get the dragged element's id
var data = event.dataTransfer.getData("text/plain");
var draggedElement = document.getElementById(data);
// Append to drop zone
event.target.appendChild(draggedElement);
}
</script>
Drag and Drop Files
You can also use drag and drop to upload files from the user's computer:
File Upload with Drag and Drop
<style>
.file-dropzone {
width: 400px;
height: 200px;
border: 3px dashed #ccc;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 18px;
color: #999;
}
.file-dropzone.highlight {
border-color: #4CAF50;
background: #f0f8f0;
}
</style>
<div class="file-dropzone"
ondrop="handleDrop(event)"
ondragover="handleDragOver(event)"
ondragenter="handleDragEnter(event)"
ondragleave="handleDragLeave(event)">
Drag files here to upload
</div>
<div id="file-list"></div>
<script>
function handleDragOver(event) {
event.preventDefault();
event.dataTransfer.dropEffect = 'copy';
}
function handleDragEnter(event) {
event.target.classList.add('highlight');
}
function handleDragLeave(event) {
event.target.classList.remove('highlight');
}
function handleDrop(event) {
event.preventDefault();
event.target.classList.remove('highlight');
// Get the dropped files
var files = event.dataTransfer.files;
// Display file information
var output = '<h3>Files:</h3><ul>';
for (var i = 0; i < files.length; i++) {
output += '<li>' + files[i].name + ' (' + files[i].size + ' bytes)</li>';
}
output += '</ul>';
document.getElementById('file-list').innerHTML = output;
// Here you would typically upload the files
// uploadFiles(files);
}
</script>
Sortable List Example
Drag to Reorder List Items
<style>
.sortable-list {
list-style: none;
padding: 0;
width: 300px;
}
.sortable-list li {
padding: 15px;
margin: 5px 0;
background: #f5f5f5;
border: 1px solid #ddd;
cursor: move;
border-radius: 5px;
}
.sortable-list li.dragging {
opacity: 0.5;
}
</style>
<ul class="sortable-list" id="sortable">
<li draggable="true">Item 1</li>
<li draggable="true">Item 2</li>
<li draggable="true">Item 3</li>
<li draggable="true">Item 4</li>
<li draggable="true">Item 5</li>
</ul>
<script>
const list = document.getElementById('sortable');
const items = list.querySelectorAll('li');
let draggedItem = null;
items.forEach(item => {
item.addEventListener('dragstart', function() {
draggedItem = this;
this.classList.add('dragging');
});
item.addEventListener('dragend', function() {
this.classList.remove('dragging');
draggedItem = null;
});
item.addEventListener('dragover', function(e) {
e.preventDefault();
if (this === draggedItem) return;
// Get position
const afterElement = getDragAfterElement(list, e.clientY);
if (afterElement == null) {
list.appendChild(draggedItem);
} else {
list.insertBefore(draggedItem, afterElement);
}
});
});
function getDragAfterElement(container, y) {
const draggableElements = [...container.querySelectorAll('li:not(.dragging)')];
return draggableElements.reduce((closest, child) => {
const box = child.getBoundingClientRect();
const offset = y - box.top - box.height / 2;
if (offset < 0 && offset > closest.offset) {
return { offset: offset, element: child };
} else {
return closest;
}
}, { offset: Number.NEGATIVE_INFINITY }).element;
}
</script>
Drag and Drop Best Practices
Best Practices
- Visual Feedback: Show clear visual indicators during drag operations
-
Cursor Changes: Use
cursor: move
on draggable elements - Highlight Drop Zones: Change appearance when dragging over valid drop targets
-
Prevent Default: Always call
preventDefault()
on dragover - Handle All Events: Implement dragenter, dragleave for better UX
- Mobile Support: Consider touch events for mobile devices
- Accessibility: Provide keyboard alternatives for drag and drop
- Error Handling: Handle cases where drop is not allowed
- Performance: Avoid heavy operations in drag event handlers
- File Validation: Validate file types and sizes when handling file drops
⚠️ Browser Compatibility
The Drag and Drop API is well-supported in modern browsers, but mobile support may require additional libraries like interact.js or SortableJS for touch events.