HTML Drag and Drop
Previously, Geolocation asked the browser for latitude and longitude after permission. This lesson leaves coordinates and introduces HTML Drag and Drop: marking what can be dragged, carrying a small payload with dataTransfer, and deciding what happens when the user drops onto a target. Your HTML still loads a script; that script wires dragstart, dragover, and drop. Scope stays practical — draggable, preventDefault on dragover, move-or-label on drop — not sortable-library products, file-upload apps, or a full accessibility engineering course.
Why drag and drop in an HTML course
Beginners often want a “drag this card into a box” demo. Native DnD is the common first API for that pointer gesture. After geolocation’s “JS reads a permitted fix,” this lesson’s split is different: HTML marks what may be dragged; JS owns event handlers and drop meaning for that page. You need draggable="true", dataTransfer on dragstart, preventDefault on dragover, and a calm drop handler — enough for intro UIs without shipping a board library or building a touch polyfill.
Direct answer
1) Set draggable="true" on the element you want to drag (many images/links are already draggable by default).
2) On dragstart, call event.dataTransfer.setData("text/plain", …) with a small payload (an id or label).
3) On the drop target, listen for dragover and call event.preventDefault() — otherwise the browser may refuse to fire drop.
4) On drop, call preventDefault() again, read getData, then move a node or update the UI.
5) There is no special “drop zone” tag — any element can be a target if you attach listeners.
6) When the action matters, offer a button or keyboard path that does the same job. DnD is a pointer convenience, not the only way.
📊 dragstart vs dragover vs drop
| Topic | dragstart | dragover | drop |
|---|---|---|---|
| Typical role | Start drag; set dataTransfer | Allow drop (preventDefault) | Apply the result |
| Runs on | Draggable source | Potential target (often) | Drop target |
| Must preventDefault? | Usually no | Yes — so drop can fire | Yes — avoid default navigation quirks |
| Beginner payload | setData("text/plain", id) | — | getData + move/label |
| This course depth | Required | Required | Required (simple move/label) |
Tiny move-into-zone demo
A blue box is marked draggable="true". On drop into the dashed zone, the script appends that node into the zone. dragover must call preventDefault or the drop may never fire.
<div id="item" draggable="true" style="padding:8px;background:#cdf;width:120px;">Drag me</div>
<div id="zone" style="margin-top:12px;padding:24px;border:2px dashed #666;">Drop here</div>
<script>
const item = document.getElementById("item");
const zone = document.getElementById("zone");
item.addEventListener("dragstart", function (e) {
e.dataTransfer.setData("text/plain", "item");
});
zone.addEventListener("dragover", function (e) {
e.preventDefault();
});
zone.addEventListener("drop", function (e) {
e.preventDefault();
zone.appendChild(item);
});
</script>
Reading the move-into-zone calls
draggable="true"tells the browser the element may start a drag gesturedragstartis where you usually calldataTransfer.setDatadragover+preventDefault()is the classic “allow drop here” signaldropis where you change the DOM or UI — hereappendChild(item)- Without
preventDefaultondragover, many browsers never run yourdrophandler - Unlike Geolocation, nothing asks for device coordinates — this is pointer + DOM
- Keep the demo small: one source, one zone, one clear result
dataTransfer payload demo
Sometimes you do not move the same node — you carry a string payload and show it on drop. That pattern is useful when several sources share one target.
<p id="a" draggable="true" style="display:inline-block;padding:6px;background:#fec;margin-right:8px;">Alpha</p>
<p id="b" draggable="true" style="display:inline-block;padding:6px;background:#cfe;margin-right:8px;">Beta</p>
<div id="tray" style="margin-top:12px;padding:16px;border:2px dashed #444;">Drop a label here</div>
<pre id="note"></pre>
<script>
const tray = document.getElementById("tray");
const note = document.getElementById("note");
function arm(id, label) {
document.getElementById(id).addEventListener("dragstart", function (e) {
e.dataTransfer.setData("text/plain", label);
});
}
arm("a", "Alpha");
arm("b", "Beta");
tray.addEventListener("dragover", function (e) {
e.preventDefault();
});
tray.addEventListener("drop", function (e) {
e.preventDefault();
note.textContent = "Dropped: " + e.dataTransfer.getData("text/plain");
});
</script>
Reading the dataTransfer idea
setData/getDatamove a small string betweendragstartanddrop- MIME type
"text/plain"is the beginner-friendly choice - Multiple sources can share one target by writing different labels
- Still not a file-upload product — we only pass a short string
- Still not Geolocation — no permission prompt for coordinates
- Choose move-node vs payload-label by what the UI should show after drop
- Next optional lesson: web workers run scripts off the main thread — a different browser capability
Choosing when to use DnD
- User rearranges a visible card into a clearly marked zone: good intro DnD fit
- Critical action with no keyboard or button path: bad — add an alternative
- Saving a theme preference: that was Web Storage, not DnD
- Reading GPS coordinates: that was Geolocation (previous lesson), not DnD
- Full kanban / sortable library / file dropzone product: beyond this HTML intro
- Touch-only devices with weak native DnD: plan a tap/button fallback early
Practice — drag, drop, and label
- Paste the move-into-zone demo; drag the box into the dashed area; confirm it moves.
- Remove
preventDefaultfromdragovertemporarily; confirm drop often stops working; restore it. - Paste the dataTransfer demo; drop Alpha and Beta; confirm the
<pre>label updates. - (Optional) Add a button that appends the item into the zone without dragging — same result.
- Write one sentence: Geolocation reads permitted coordinates; Drag and Drop moves or labels with pointer events.
- Prefer a real browser window over relying only on
file://quirks if a demo misbehaves. - Peek ahead: web workers run background scripts — not drag gestures.
Easy mistakes
- Forgetting
preventDefaultondragoversodropnever fires - Building DnD-only UIs with no keyboard or button alternative
- Expecting a special HTML
<dropzone>tag instead of listeners on any element - Confusing Drag and Drop with Geolocation (pointer payloads ≠ device coordinates)
- Overusing DnD when a simple “Move” button would teach the same idea faster
- Treating
dataTransferas a secret vault or a full file pipeline in this intro - Treating this intro as a full sortable, touch, or accessibility certification course
Summary
- HTML Drag and Drop uses
draggable,dataTransfer, anddragstart/dragover/drop - Call
preventDefaultondragover(and usually ondrop) so the gesture completes - HTML marks sources; script defines what a drop means (move node or show a payload)
- Offer a non-drag path when the action matters
- Geolocation was permitted coordinates; this lesson is pointer-driven move/label
- Next: HTML web workers for background scripts off the main thread
🧠 Test Your Knowledge
Test Your Knowledge
Challenge yourself with this interactive quiz and see how well you understand the topic
📝 Instructions
- Read each question carefully
- Select the best answer for each question
- You can retake the quiz as many times as you want
- Your progress will be shown at the top