Welcome to a quick tutorial on how to create a drag and drop sortable list with HTML and Javascript. Once upon a time in the Dark Ages of the Internet, implementing drag-and-drop is a massive task that involves a lot of coding with 3rd party libraries. But ever since HTML5, it has been made a native feature and we no longer have to fight with digital dragons.
In the simplest design, drag-and-drop in HTML and Javascript only requires:
- Create draggable items by attaching the draggable property –
<div draggable>Drag This</div>
- Define the dropzone –
<div id="drop">Drop Here</div>
- Attach a drop listener in Javascript –
document.getElementById("drop").ondrop = () => { DO SOMETHING };
That covers the basics, but how can we create a sortable list with this? Read on for an example!
ⓘ I have included a zip file with all the source code at the start of this tutorial, so you don’t have to copy-paste everything… Or if you just want to dive straight in.
TABLE OF CONTENTS
DOWNLOAD & DEMO
Firstly, here is the download link to the example code as promised.
QUICK NOTES
If you spot a bug, feel free to comment below. I try to answer short questions too, but it is one person versus the entire world… If you need answers urgently, please check out my list of websites to get help with programming.
EXAMPLE CODE DOWNLOAD
Click here to download the source code, I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORTABLE LIST DEMO
- First
- Second
- Third
- Forth
- Fifth
DRAG-AND-DROP SORTABLE LIST
All right, let us now get into the details of how the drag-and-drop list works.
STEP 1) THE HTML
<!-- (A) LOAD CSS + JS -->
<link rel="stylesheet" href="sort-list.css">
<script src="sort-list.js"></script>
<!-- (B) THE LIST -->
<ul id="sortlist">
<li>First</li>
<li>Second</li>
<li>Third</li>
<li>Forth</li>
<li>Fifth</li>
</ul>
<!-- (C) CREATE SORTABLE LIST -->
<script>
slist(document.getElementById("sortlist"));
</script>
For you guys who just want to use this as a “plugin” without reading the rest of the tutorial:
- Load the CSS and Javascript. Doh.
- Define the
<ul>
or<ol>
as usual. Take note that this simple example will only work with a flat one-level list. - Use the
slist(TARGET)
function on window load to initiate the sortable list.
STEP 2) THE CSS
/* (A) LIST STYLES */
.slist {
list-style: none;
padding: 0;
margin: 0;
}
.slist li {
margin: 10px;
padding: 15px;
border: 1px solid #dfdfdf;
background: #f5f5f5;
}
/* (B) DRAG-AND-DROP HINT */
.slist li.hint {
border: 1px solid #ffc49a;
background: #feffb4;
}
.slist li.active {
border: 1px solid #ffa5a5;
background: #ffe7e7;
}
These are just some simple cosmetic styles for the sortable list.
- The Javascript will attach a
.slist
class to the container. In this section, we remove the default bullet points and make the list look a little better. - The
.hint
class is used to highlight the possible dropzones, and.active
when the draggable is hovering over the dropzone.
STEP 3) THE JAVASCRIPT
function slist (target) {
// (A) SET CSS + GET ALL LIST ITEMS
target.classList.add("slist");
let items = target.getElementsByTagName("li"), current = null;
// (B) MAKE ITEMS DRAGGABLE + SORTABLE
for (let i of items) {
// (B1) ATTACH DRAGGABLE
i.draggable = true;
// (B2) DRAG START - YELLOW HIGHLIGHT DROPZONES
i.ondragstart = e => {
current = i;
for (let it of items) {
if (it != current) { it.classList.add("hint"); }
}
};
// (B3) DRAG ENTER - RED HIGHLIGHT DROPZONE
i.ondragenter = e => {
if (i != current) { i.classList.add("active"); }
};
// (B4) DRAG LEAVE - REMOVE RED HIGHLIGHT
i.ondragleave = () => i.classList.remove("active");
// (B5) DRAG END - REMOVE ALL HIGHLIGHTS
i.ondragend = () => { for (let it of items) {
it.classList.remove("hint");
it.classList.remove("active");
}};
// (B6) DRAG OVER - PREVENT THE DEFAULT "DROP", SO WE CAN DO OUR OWN
i.ondragover = e => e.preventDefault();
// (B7) ON DROP - DO SOMETHING
i.ondrop = e => {
e.preventDefault();
if (i != current) {
let currentpos = 0, droppedpos = 0;
for (let it=0; it<items.length; it++) {
if (current == items[it]) { currentpos = it; }
if (i == items[it]) { droppedpos = it; }
}
if (currentpos < droppedpos) {
i.parentNode.insertBefore(current, i.nextSibling);
} else {
i.parentNode.insertBefore(current, i);
}
}
};
}
}
Right, the Javascript looks like quite a handful at first, but keep calm and study closely.
- Attach a
.slist
CSS class to the list, and get all the<li>
list items. - Loop through all the <li>, attach a load of drag-and-drop listeners.
- (B1) Set
<li draggable>
. - (B2) On drag start, attach
.hint
to highlight all the list items. - (B3) When the dragged element hovers a list item, add
.active
to show a different highlight color. - (B4) When the dragged element leaves a list item, remove
.active
. - (B5) When the drag stops, remove all
.hint
and.active
CSS classes. - (B6) Necessary. Prevents the default browser action, so we can define our own.
- (B7) Some Math. Does the actual sorting on dropped.
- (B1) Set
EXTRA BITS & LINKS
That’s it for the example code, and here are some extras and links that you may find useful.
COMPATIBILITY CHECKS – NOTES ON MOBILE SUPPORT
- Arrow Functions – CanIUse
- Draggable – CanIUse
- Drag and Drop – CanIUse
Guess what? Mobile devices and browsers still don’t properly support drag-and-drop at the time of writing. If you have to do drag-and-drop on mobile devices, the best bet is to use a “polyfill” such as DragDropTouch and MobileDragDrop.
THE SUMMARY – DRAG-DROP EVENTS
Event | Description |
dragstart |
Fired when the drag starts. |
dragend |
Fired when the drag stops. |
drag |
As the element is being dragged around. |
dragenter |
When the mouse enters the boundaries of an element. |
dragover |
As the element is being dragged over another element. |
dragleave |
When the mouse exits the boundaries of an element. |
drop |
Fired when the element is being dropped. |
LINK & REFERENCES
- HTML draggable – MDN
- HTML Drag and Drop API – MDN
- Example On CodePen – JS Drag-And-Drop Sortable List
TUTORIAL VIDEO
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you to better understand how vanilla Javascript drag and drop works. If you have anything to add to this guide, please feel free to comment below. Good luck and happy coding!
I see it’s not working with mobile view, can you please advise if it could be possible to fix?
As above, see “COMPATIBILITY CHECKS – NOTES ON MOBILE SUPPORT”.
Great code. Short & sweet. I adapted it to sort an image gallery.
Thanks for sharing.
Thank you!
I wanted to have a red line showing where the item was dropped so I used `.active { border-top: 2px solid red; }` as style and simplified the drop code to just
evt.preventDefault();
if (this != current)
this.parentNode.insertBefore(current, this);
which made it always work as expected. Though this only really works well for small (height) elements as it is kind of unintuitive when the red line is a long distance away from the cursor.
Also removed the getElementById (to be able to pass element references directly instead of only IDs)
Are you sure it “always works as intended” after “simplifying” the drop calculations? There is a good reason why I did that. 😉
Hint: Try swapping the first with the second. You might want to do more calculations to check if it is border-top or border-bottom.
I’m in agreement with CN. It is ridiculously difficult to do something that supposedly doesn’t take much code to do at all. * REMOVED – UNINTELLIGIBLE DUMB TROLL NOISES *
Agree with what? Guy only posted a question. There was no mention of “difficult”, nor negative suggestions. Learn how to read basic English and stop embarrassing yourself first?
P.S. Since you claim “it doesn’t take much code to do” – I am interested to see how a genius such as yourself make an already barebones example even shorter. While showcasing all the drag-and-drop events PLUS sort capability.
https://code-boxx.com/faq/#nolike
I’m doing a javascript course. Recently, I built a “to do” list, that saved the list of to dos in local storage.
I added your script to the app and it worked, more or less out of the box!
However, I can’t figure out how to add the positions to local storage – data in local storage, as you know, always gets stored as a string. What strings could be stored that relate to the position of the list items?
I’ve googled this, but haven’t found any answers.
Not going to do your homework… so hint:
1) Add ID to list items using custom data attributes.
2) After drop – Get all list items.
3) Loop through, gather the new sort order into an array.
4) JSON encode, save it.
https://developer.mozilla.org/en-US/docs/Learn/HTML/Howto/Use_data_attributes
Thanks very much for the hints (and the link) – will have a go at that!