Drag/Drop order items

Expanded on https://web.dev/drag-and-drop/#:~:text=To%20make%20an%20object%20draggable,any%20markup%20on%20your%20page.

by PhilQ

HTML

<div id="item-container" class="container">
  <div draggable="true" class="box"><div class="box-inner">A</div></div>
  <div draggable="true" class="box"><div class="box-inner">B</div></div>
  <div draggable="true" class="box"><div class="box-inner">C</div></div>
	<div draggable="true" class="box"><div class="box-inner">D</div></div>
	<div draggable="true" class="box"><div class="box-inner">E</div></div>
</div>

CSS

*, ::before, ::after {
	margin: 0;
	padding: 0;
	box-sizing: border-box;
}
body {
	padding: 10px;
}

.container {
  display: flex;
	flex-wrap: wrap;
	justify-content: flex-start;
	gap: 10px;
	padding: 10px 0 0 10px;
}
.box {
	position: relative;
	display: flex;
	align-items: stretch;
	flex-shrink: 0;
	flex-grow: 0;
	flex-basis: calc(25% - 10px);
  cursor: move;
}
.box-inner,
.box::before,
.box::after {
	pointer-events: none;
	display: inline-flex;
	width: 100%;
	margin: 0;
  border: 3px solid #666;
  background-color: #ddd;
  border-radius: 0.5em;
  padding: 10px;
	transition: none;
}
.box::before,
.box::after {
	width: 0;
	background-color: #ddd;
	border: 3px dotted #666;
	transition: width 0.15s ease, margin 0.15s ease;
}
.box.over.before::before,
.box.over.after::after {
	content: '';
	width: calc(50% - 5px);
}
.box.over .box-inner {
	transition: width 0.15s ease, margin 0.15s ease;
  /* border: 3px dotted #666; */
}
.box.over.before .box-inner {
	/* right half */
	width: calc(50% - 5px);
	margin-left: 10px;
}
.box.over.after .box-inner {
	/* left half */
	width: calc(50% - 5px);
	margin-right: 10px;
}
.box.dragging {
	opacity: 0.3;
}
.box.over.dragging .box-inner {
	border: 3px dotted #666;
}

JavaScript

/**
 * Helpers
 */
function getChildIndex(node) {
  return node.parentNode ? Array.prototype.indexOf.call(
		node.parentNode.childNodes,
		node
	) : 0;
}
function getChildElementIndex(node) {
  return node.parentNode ? Array.prototype.indexOf.call(
		node.parentNode.children,
		node
	) : 0;
}


/**
 * Main
 */
function handleDragStart(e) {
	items.forEach(function(item) {
		item.dataset.i = getChildIndex(item);
	});

	this.classList.add('dragging');   
	draggedEl = this;

	e.dataTransfer.effectAllowed = 'move';
	e.dataTransfer.setData(
		'text/plain',
		this.dataset.i
	);
}

function handleDragEnd(e) {
	this.classList.remove('dragging');
	document.querySelector('.over').classList.remove('over');
	document.querySelector('.before').classList.remove('before');
	document.querySelector('.after').classList.remove('after');
}

function handleDragOver(e) {
	if (e.preventDefault) {
		e.preventDefault();
	}

	return false;
}

function handleDragEnter(e) {
	this.classList.add('over');
	if (this.dataset.i < draggedEl.dataset.i) {
		this.classList.add('before');
	} else if (this.dataset.i > draggedEl.dataset.i) {
		this.classList.add('after');
	}
}

function handleDragLeave(e) {
	this.classList.remove('over', 'before', 'after');
}

function handleDrop(e) {
	if (e.preventDefault) {
		e.preventDefault();
	}

	if (this.dataset.i < draggedEl.dataset.i) {
		this.before(draggedEl);
	} else if (this.dataset.i > draggedEl.dataset.i) {
		this.after(draggedEl);
	}

	return false;
}

let items = null;
let draggedEl = null;

document.addEventListener('DOMContentLoaded', (event) => {
  items = document.querySelectorAll('.container .box');
	items.forEach(function(item, i) {
		item.addEventListener('dragstart', handleDragStart, false);
    item.addEventListener('dragover', handleDragOver, false);
    item.addEventListener('dragenter', handleDragEnter, false);
    item.addEventListener('dragleave', handleDragLeave, false);
    item.addEventListener('dragend', handleDragEnd,...