Chapter 1 of ?
html 8 min read

HTML Mastery — Chapter 17: HTML Drag & Drop API

1. Fundamentals of HTML5 Drag & Drop (draggable="true")

The HTML5 Drag & Drop API enables native dragging of DOM elements across drop targets without relying on heavy external JavaScript libraries.

  • Default Draggable Elements: Text selections, <img> elements, and <a href="..."> hyperlinks are draggable by default.
  • Custom Draggable Elements: Any HTML element (e.g. <div>, <li>, <article>) becomes draggable by adding the global attribute draggable="true".
Boolean Value Notice: The draggable attribute is NOT a standard boolean attribute. You must explicitly specify draggable="true" or draggable="false" (omitting the value does not default to true).

Making a Custom Box Draggable

draggable-example.html
<!-- Custom Draggable Element --> <div draggable="true" ondragstart="event.dataTransfer.setData('text/plain', 'Item 101')" style="background:#4f46e5;color:white;padding:12px;border-radius:8px;cursor:grab;"> 📦 Moveable Package </div>
Try It Yourself »
Try It Yourself — Toggle `draggable` Attribute Live

Toggle the draggable attribute below to test dragging behavior on/off:

Current state: draggable="true"
Draggable Box (Try dragging me!)

2. Drag & Drop Event Lifecycle & Flow

The Drag & Drop lifecycle split into two distinct event streams: events fired on the Drag Source element, and events fired on the Drop Target zone.

Drag and Drop Event Lifecycle & Transfer Data Flow
DRAG SOURCE draggable="true" Source Events 1. dragstart 2. drag (continuous) 3. dragend dataTransfer Object setData('text/plain', payload) ➔ getData('text/plain') DROP TARGET preventDefault() on dragover Target Events 1. dragenter 2. dragover (required) 3. dragleave 4. drop

Handling Source and Target Events

const item = document.getElementById('drag-item'); const zone = document.getElementById('drop-zone'); // Source Listener item.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', item.id); }); // Target Listeners (MUST preventDefault on dragover) zone.addEventListener('dragover', (e) => { e.preventDefault(); // Unlocks drop functionality }); zone.addEventListener('drop', (e) => { e.preventDefault(); const id = e.dataTransfer.getData('text/plain'); zone.appendChild(document.getElementById(id)); });
Try It Yourself »
Try It Yourself — Real-Time Event Logger

Drag the package into the target zone to inspect event triggers live:

Live Drag Box
Drop Target Area
Latest Triggered Event:Waiting for drag action...

3. The dataTransfer Object & Payload Storage

The event.dataTransfer object holds the payload passed from the drag source to the drop target during the drag operation.

Method / Property Description
setData(format, data) Stores data payload. Standard formats include 'text/plain', 'text/html', 'text/uri-list', or JSON strings.
getData(format) Retrieves stored payload string inside the drop event listener.
clearData([format]) Clears all data or specified format data from payload storage.
effectAllowed Specifies cursor feedback allowed by source: 'copy', 'move', 'link', 'copyMove', 'all', 'none'.
dropEffect Specifies actual drop effect chosen by target: 'copy', 'move', 'link', 'none'.

Passing Complex JSON Payloads

// Drag Source item.addEventListener('dragstart', (e) => { const payload = JSON.stringify({ id: 404, title: 'Fix CSS Bug', priority: 'High' }); e.dataTransfer.setData('application/json', payload); }); // Drop Target zone.addEventListener('drop', (e) => { e.preventDefault(); const raw = e.dataTransfer.getData('application/json'); const data = JSON.parse(raw); console.log(`Task ID: ${data.id}, Priority: ${data.priority}`); });
Try It Yourself »
Try It Yourself — Multi-Format Payload Inspector

Drag custom payload cards below into the inspector to extract data:

JSON Card (#Task-77)
Plaintext Card ("Deploy v2")
Drop payload card here to inspect dataTransfer content

4. Drop Target Visual Feedback & Cursor Modification

Providing clear visual feedback when an element hovers over a valid drop target is crucial for user experience.

Toggling Active Classes on Drag Enter / Leave

const dropZone = document.getElementById('drop-zone'); dropZone.addEventListener('dragenter', (e) => { e.preventDefault(); dropZone.classList.add('over'); // Highlight target area }); dropZone.addEventListener('dragleave', () => { dropZone.classList.remove('over'); // Remove highlight }); dropZone.addEventListener('drop', (e) => { e.preventDefault(); dropZone.classList.remove('over'); // Process drop payload... });
Try It Yourself »
Try It Yourself — Drop Effect & Visual Feedback Demo

Drag the element into different drop effect zones to observe cursor modifications:

Effect Demo Box
Copy Zone (effectAllowed="copy")
Move Zone (effectAllowed="move")

5. Interactive Project: Drag-and-Drop Task Board

Putting it all together: build a production-grade Kanban Task Board where tasks can be dragged between status columns ("To Do", "In Progress", "Done").

Kanban Board Drag & Drop Architecture

// Add dragstart listener to all Kanban cards document.querySelectorAll('.kanban-card').forEach(card => { card.addEventListener('dragstart', (e) => { e.dataTransfer.setData('text/plain', card.id); card.classList.add('dragging'); }); }); // Add drop listeners to all Kanban column lists document.querySelectorAll('.kanban-list').forEach(list => { list.addEventListener('dragover', (e) => { e.preventDefault(); list.classList.add('over'); }); list.addEventListener('dragleave', () => list.classList.remove('over')); list.addEventListener('drop', (e) => { e.preventDefault(); list.classList.remove('over'); const cardId = e.dataTransfer.getData('text/plain'); const card = document.getElementById(cardId); if (card) list.appendChild(card); }); });
Try It Yourself »
Try It Yourself — Live Drag-and-Drop Task Board

Drag cards between status columns to manage tasks live:

To Do 2
🚀 Setup Geolocation
🎨 Refine CSS Variables
In Progress 1
⚡ Build Drag & Drop Board
Done 1
✅ Complete Chapter 16

Hands-On Challenge: Build a File Drop Zone Uploader

Create a file upload drop zone using event.dataTransfer.files that highlights green on dragenter and displays the dropped file's name and file size in KB.

Launch Code Playground & Try »

Chapter 17 Key Takeaways

  • Add draggable="true" to make custom HTML elements draggable.
  • Must call event.preventDefault() inside ondragover for target elements to accept drops.
  • Use event.dataTransfer.setData(format, data) on dragstart to attach payloads.
  • Use event.dataTransfer.getData(format) on drop to extract payload data.
  • Use effectAllowed and dropEffect to control cursor icons (`copy`, `move`, `link`).
Done with this chapter?
Mark it complete to track your progress and unlock your certificate.
Next Up

Learner Reviews

Write a Review
Share your experience to help other learners.
Your Rating *