HTML drag and drop (Widely available) moves data, not elements. A draggable="true" element's dragstart handler stores strings in event.dataTransfer; a drop target must cancel dragover to accept a drop, and its drop handler reads the data back.
<style>body { font: 15px system-ui; display: flex; gap: 8px; } [draggable] { background: #e3f2fd; }
div { width: 190px; min-height: 60px; border: 2px dashed #90a4ae; padding: 4px; }</style>
<div><b>To do</b><p draggable="true">Add tests</p><p draggable="true" id="bug">Fix bug #42</p></div>
<div id="done"><b>Done</b></div>
<script>
addEventListener('dragstart', (e) => e.dataTransfer.setData('text/plain', e.target.id));
done.ondragover = (e) => e.preventDefault(); // allow dropping here
done.ondrop = (e) => {
e.preventDefault(); // skip the default handling
done.append(document.getElementById(e.dataTransfer.getData('text/plain')));
};
const dataTransfer = new DataTransfer();
bug.dispatchEvent(new DragEvent('dragstart', { bubbles: true, dataTransfer }));
done.dispatchEvent(new DragEvent('drop', { cancelable: true, dataTransfer }));
</script>
Desktop files arrive in dataTransfer.files (FileReader and Blob), and getData() stays empty until drop so pages cannot snoop on a passing drag. Add Move buttons for keyboard users; SortableJS 31,183 (https://github.com/SortableJS/Sortable 31,183 ) (MIT) builds touch-ready sortable lists.