HTML Tutorial · HTML5 Features · Lesson 30 of 34

HTML Drag and Drop

Make elements draggable and handle drops with the HTML Drag and Drop API, plus a keyboard alternative.

The basics

  1. Mark an element draggable="true".
  2. In dragstart, put data on event.dataTransfer.
  3. On the drop target, call preventDefault() in dragover (this allows dropping).
  4. In drop, read the data and update the page.
A tiny board with drag and drop and a button alternativeTry it yourself
<style>
  .col { display: inline-block; vertical-align: top; width: 140px; min-height: 120px; border: 2px dashed #999; margin: 4px; padding: 6px; }
  .col.over { background: #eef2ff; }
  .task { background: #fde68a; padding: 4px 6px; margin: 4px 0; cursor: grab; }
</style>
<div class="col" id="todo"><b>To do</b>
  <div class="task" draggable="true" id="t1">Write docs <button data-move="t1">Done</button></div>
  <div class="task" draggable="true" id="t2">Fix bug <button data-move="t2">Done</button></div>
</div>
<div class="col" id="done"><b>Done</b></div>
<script>
  const done = document.getElementById("done");
  document.querySelectorAll(".task").forEach((t) =>
    t.addEventListener("dragstart", (e) => e.dataTransfer.setData("text/plain", t.id)));
  done.addEventListener("dragover", (e) => { e.preventDefault(); done.classList.add("over"); });
  done.addEventListener("dragleave", () => done.classList.remove("over"));
  done.addEventListener("drop", (e) => {
    e.preventDefault();
    done.classList.remove("over");
    done.append(document.getElementById(e.dataTransfer.getData("text/plain")));
  });
  // keyboard and touch alternative
  document.addEventListener("click", (e) => {
    const id = e.target.dataset.move;
    if (id) { done.append(document.getElementById(id)); e.target.remove(); }
  });
</script>

Files

Dropping files from the desktop works the same way: read event.dataTransfer.files in the drop handler, as upload areas do.

Accessibility

Drag and drop needs a pointer. Always provide a keyboard and touch alternative, such as "Move to Done" buttons or a select menu. The example includes one.

Test yourself

Why must the drop target call preventDefault() in its dragover handler?

  1. To stop the page scrolling
  2. By default elements don't accept drops; cancelling dragover allows dropping
  3. To copy the dragged data
  4. It's optional and has no effect
Show answer

Answer: By default elements don't accept drops; cancelling dragover allows dropping

Without it, the drop event never fires.