//HTML <div class="container"> <ul class="list"> <li class="list--item" draggable="true">1</li> <li class="list--item" draggable="true">2</li> <li class="list--item" draggable="true">3</li> <li class="list--item" draggable="true">4</li> </ul> </div> //CSS * { padding: 0; box-sizing: border-box; } body { height: 100vh; display: flex; justify-content: center; align-items: center; } .container { width: min(90%, 500px); background-color: #333; } .list { display: flex; flex-direction: column; gap: 1rem; list-style: none; padding: 1rem; } .list--item { padding: 1rem; background-color: #efefef; } .dragging { background-color: rgba(0, 0, 0, 0.7); color: white; transition: 0.3s; } //JS const list = document.querySelector('.list'); const items = document.querySelectorAll('.list--item'); const getDragAfterElement = (y) => { //Selects all the elements in the container that are not being dragged const draggableElements = [ ...list.querySelectorAll('.list--item:not(.dragging)'), ]; //Loop through the elements' list and determine which single element is right after our mouse cursor based on the y position that we pass in return draggableElements.reduce( (closest, child) => { const box = child.getBoundingClientRect(); //Get half of the box on the y axis const offset = y - box.top - box.height / 2; //First the number needs to be negative, that is how we know that we are hovering over another child element, but we need the closest one, so the one which offset is the smallest if (offset < 0 && offset > closest.offset) { return { offset: offset, element: child }; } else { return closest; } }, { offset: Number.NEGATIVE_INFINITY } ).element; }; items.forEach((item) => { item.addEventListener('dragstart', () => { item.classList.add('dragging'); }); item.addEventListener('dragend', () => { item.classList.remove('dragging'); }); }); list.addEventListener('dragover', (e) => { e.preventDefault(); const draggable = document.querySelector('.dragging'); const afterElement = getDragAfterElement(e.clientY); if (afterElement == null) { //going to be added as the last child if no element is after list.appendChild(draggable); } else { //going to be added as before the next element list.insertBefore(draggable, afterElement); } });