Drag and Drop API
Dragging a file from the desktop into a browser, or reordering items in a list by dragging them — both rely on the same native HTML Drag and Drop API. It's older and has more rough edges than most APIs covered in this course, but understanding the actual event sequence makes it far less mysterious than it first appears.
Making an Element Draggable
draggable="true" is required on the source element — most elements default to non-draggable, with images and links being the only common exceptions that are draggable automatically.
The Full Event Sequence
| Event | Fires on | Purpose |
|---|---|---|
| dragstart | The draggable source element | Set up dataTransfer with what's being dragged |
| dragover | Every potential drop target, repeatedly | Must call preventDefault() or the drop is rejected entirely |
| drop | The actual drop target | Read dataTransfer, do the actual work |
| dragend | The original source element | Clean up — runs whether the drop succeeded or was cancelled |
dragover's handler must explicitly call event.preventDefault() to tell the browser "yes, this is a valid place to drop." Skipping this one line is responsible for the vast majority of "my drag and drop isn't working at all" debugging sessions.
dataTransfer — Carrying Information Between Source and Target
setData/getData work with a MIME-type-like key, allowing several formats of the same data to be set simultaneously — useful when dragging between different applications (a browser tab and a desktop file manager) that each expect a different data format.
Dragging Files From the Desktop
Dragging files from the operating system into the browser populates event.dataTransfer.files with the same FileList type the File API (next chapter) works with directly — drag-and-drop file upload and a traditional <input type="file"> ultimately produce the same kind of object to work with.
Where Native Drag and Drop Genuinely Struggles
- Touch devices. The native API is mouse-event-based at its core and doesn't translate cleanly to touch — mobile drag interactions typically need a separate, custom-built touch-event implementation.
- Visual feedback during the drag. Customising the default drag "ghost image," giving real-time visual feedback about valid/invalid drop zones, and smooth reordering animations all require considerable additional work beyond the bare API.
- Accessibility. Drag-and-drop interactions are inherently difficult for keyboard-only and screen reader users — a genuinely accessible interface needs an equivalent non-drag way to accomplish the same action (e.g. "Move up"/"Move down" buttons alongside drag handles).
Chapter 4 Quick Reference
- draggable="true" — required on the source element; images/links are draggable by default
- Event sequence: dragstart → dragover (repeatedly) → drop → dragend
- dragover MUST call preventDefault() — otherwise the drop is rejected by default; the most common bug
- dataTransfer.setData/getData — carries data between source and target, keyed by a MIME-type-like string
- event.dataTransfer.files — a real FileList when files are dragged from the desktop, same type as a file input
- Native API struggles with: touch devices, custom drag visuals, accessibility — often handled via a dedicated library instead
- Next chapter: File API — file inputs, reading files client-side