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.

Leave a Comment

Your email address will not be published. Required fields are marked *