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:

Event Fires On Description
dragstart Dragged element User starts dragging an element
drag Dragged element Element is being dragged (fires continuously)
dragenter Drop target Dragged element enters a drop target
dragover Drop target Dragged element is over a drop target
dragleave Drop target Dragged element leaves a drop target
drop Drop target Element is dropped on a drop target
dragend Dragged element Drag operation ends (success or failure)

⚠️ 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:

Method/Property Description
setData(format, data) Sets the data to be transferred
getData(format) Retrieves the data
clearData(format) Removes the data
effectAllowed Specifies allowed effects (copy, move, link)
dropEffect The actual effect (copy, move, link, none)
files Contains list of files 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

  1. Visual Feedback: Show clear visual indicators during drag operations
  2. Cursor Changes: Use cursor: move on draggable elements
  3. Highlight Drop Zones: Change appearance when dragging over valid drop targets
  4. Prevent Default: Always call preventDefault() on dragover
  5. Handle All Events: Implement dragenter, dragleave for better UX
  6. Mobile Support: Consider touch events for mobile devices
  7. Accessibility: Provide keyboard alternatives for drag and drop
  8. Error Handling: Handle cases where drop is not allowed
  9. Performance: Avoid heavy operations in drag event handlers
  10. 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.

Test Your Knowledge