AtelierCMS: drag-to-reorder gallery without a JS framework
The admin needed to reorder exhibition photos. Previous behaviour: upload order was display order, which was fine until a client uploaded 12 photos out of sequence and asked me to fix it.
The HTML5 Drag and Drop API is underused. For a simple list of thumbnails it’s completely sufficient.
<div id="gallery-sort" data-gallery="winter-2026">
{foreach $images as $img}
<div class="sort-item" draggable="true" data-id="{$img.id}">
<img src="{$img.thumb}" alt="">
</div>
{/foreach}
</div>
// ~40 lines, no dependencies
const list = document.getElementById('gallery-sort');
let dragged = null;
list.addEventListener('dragstart', e => { dragged = e.target.closest('.sort-item'); });
list.addEventListener('dragover', e => {
e.preventDefault();
const target = e.target.closest('.sort-item');
if (target && target !== dragged) {
const rect = target.getBoundingClientRect();
const after = e.clientY > rect.top + rect.height / 2;
list.insertBefore(dragged, after ? target.nextSibling : target);
}
});
list.addEventListener('dragend', () => {
const order = [...list.querySelectorAll('.sort-item')].map(el => el.dataset.id);
fetch('/admin/gallery-order', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ gallery: list.dataset.gallery, order }),
});
});
Order persists to a _order.json sidecar in the gallery directory. The public template reads this file if it exists; falls back to filename sort if not.
The only gotcha: mobile. Touch events are not fired for draggable elements by default on iOS Safari. I added a touch-action polyfill for the admin, since the clients are all desktop users anyway. Not worth solving for now.