In short
Dragging cards across a Kanban board or dropping files onto an upload box feels natural. The browser has drag and drop built in, with a few rules to learn.
The native HTML Drag and Drop API (`draggable`, `dragstart`, `drop`, etc.) lets users drag elements or files around the page — the basis of reorderable lists and file-drop zones. Native drag-and-drop has several event and browser quirks, so understanding the underlying API is useful even when a production application later adopts a dedicated library.

Think of it like this
The dabbawala handover
One dabbawala picks up the tiffin and its code says where it's going. At the destination, someone has to be ready to receive it, or it can't be handed over. In drag and drop, the drop zone must say 'I'm ready' too.
Watch it happen
The life of a drag
setData("task-1")
1/5dragstart: the user grabs the card and you store its id in the drag's dataTransfer.
The big ideas
What you need to know
draggable="true"
Links and images drag by default. For other elements, add the draggable attribute.
Carry data with it
In dragstart, use e.dataTransfer.setData to attach info, like the card's id.
Allow the drop
The drop zone must call e.preventDefault() in dragover. Without it, drop never fires.
Touch and keyboard
Native drag and drop can be patchy on touch screens and doesn't work by keyboard. Offer a button alternative too.
See it in code
Walk through the code
1// <div class="card" draggable="true" id="task-1">Fix navbar</div>2document.addEventListener("dragstart", (e) => {3 if (e.target.matches(".card")) e.dataTransfer.setData("text/plain", e.target.id);4});5 6document.querySelectorAll(".column").forEach((col) => {7 col.addEventListener("dragover", (e) => e.preventDefault()); // allow drop8 col.addEventListener("drop", (e) => {9 e.preventDefault();10 const id = e.dataTransfer.getData("text/plain");11 col.appendChild(document.getElementById(id));12 });13});1/3When any card starts dragging, attach its id to the drag as plain text.
For dropping files from the desktop, read e.dataTransfer.files in the drop handler instead. It's a FileList, same as a file input.
Save yourself the pain
Common mistakes
Oops
Adding a drop listener and wondering why it never fires.
Do this instead
Call e.preventDefault() in the dragover handler. That's what marks the element as a valid drop zone.
Oops
Dropping a file and having the browser open it in the tab.
Do this instead
Call e.preventDefault() in drop as well, so the browser doesn't take over.
Your mission
Mini Kanban board
Quick check
Your drop zone's drop event never fires. What's the most likely cause?
Go deeper
- 1Build a simple drag-and-drop file upload zone. Keep the first version small, then add one improvement after the core behavior works.
- 2Make a list of items reorderable using native drag-and-drop events. Validate your understanding by applying it in a small practical example.
- 3Consider a library (dnd-kit, react-beautiful-dnd) for complex cases — the native API is fiddly.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.