This Interactive Drag & Drop Table Sorting Panel provides a clean, modern way to manage sortable data directly within a table layout. Users can instantly rearrange rows using smooth drag-and-drop controls, visually track drop positions, delete entries, and automatically update item order values in real time.
Perfect for music playlists, queue systems, task managers, admin dashboards, media libraries, and custom web applications, the panel combines responsive styling with lightweight JavaScript for a fast, user-friendly experience.
This demo comes with the sort order at the bottom of the panel:
OrderCsv = 6:1,8:2,76:3
Each time you move an item in the list, these numbers change.
Making it easy to implement into a database.
The [Drop here] does not work in this demo, but will work on your system.
Live Template Example - Drag Drop Demo
[HTML - Dragdrop.html]
CFFCS | CarrzSynEdit: | HTML (Hyper Text Markup Language)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Table Drag Sort Demo</title>
<link href="Dragdrop.css" rel="stylesheet" />
</head>
<body>
<div class="demo-wrap">
    <h1>Table Drag Sort Demo</h1>

    <table class="dj-table" id="djPlaylistTable">
        <thead>
            <tr>
                <th class="col-pos">Order</th>
                <th class="col-track">Track</th>
                <th class="col-band">Band / Album</th>
                <th class="col-time">Time</th>
                <th class="col-actions">Action</th>
            </tr>
        </thead>
        <tbody id="trackList">
            <tr class="track-row track-item" draggable="true" data-trackid="6">
                <td class="col-pos">1</td>
                <td class="col-track"><span class="track-title">Kissin' Time</span></td>
                <td class="col-band">KISS<span class="track-album">KISS</span></td>
                <td class="col-time">03:53</td>
                <td class="col-actions"><button class="delete-btn" type="button"></button></td>
            </tr>
            <tr class="track-row track-item" draggable="true" data-trackid="8">
                <td class="col-pos">2</td>
                <td class="col-track"><span class="track-title">Love Theme from Kiss</span></td>
                <td class="col-band">KISS<span class="track-album">KISS</span></td>
                <td class="col-time">02:24</td>
                <td class="col-actions"><button class="delete-btn" type="button"></button></td>
            </tr>
            <tr class="track-row track-item" draggable="true" data-trackid="76">
                <td class="col-pos">3</td>
                <td class="col-track"><span class="track-title">Then She Kissed Me</span></td>
                <td class="col-band">KISS<span class="track-album">Love Gun</span></td>
                <td class="col-time">03:02</td>
                <td class="col-actions"><button class="delete-btn" type="button"></button></td>
            </tr>
            <tr id="queue-end-dropzone" class="queue-drop-row">
                <td colspan="5">Drop here</td>
            </tr>
        </tbody>
    </table>

    <div class="order-output" id="orderOutput"></div>
</div>
<script src="Dragdrop.js"></script>
</body>
</html>

[CSS - Dardrop.css]
CFFCS | CarrzSynEdit: | CSS (Cascading Style Sheets)
    body{
        font-family: Arial, sans-serif;
        background:#111827;
        color:#f9fafb;
        padding:30px;
    }

    .demo-wrap{
        max-width:900px;
        margin:0 auto;
        background:#1f2937;
        border:1px solid #374151;
        border-radius:10px;
        padding:20px;
    }

    h1{
        margin-top:0;
        font-size:24px;
    }

    .dj-table{
        width:100%;
        border-collapse:collapse;
        table-layout:fixed;
    }

    .dj-table th,
    .dj-table td{
        padding:10px 12px;
        border-bottom:1px solid #374151;
        text-align:left;
        vertical-align:middle;
    }

    .dj-table th{
        color:#93c5fd;
        font-size:13px;
        text-transform:uppercase;
        letter-spacing:.04em;
    }

    .col-pos{width:70px;}
    .col-track{width:auto;}
    .col-band{width:230px;}
    .col-time{width:80px; text-align:right;}
    .col-actions{width:70px; text-align:center;}

    .track-row{
        cursor:grab;
        user-select:none;
    }

    .track-row:active{
        cursor:grabbing;
    }

    .track-row.dragging{
        opacity:.45;
    }

    .track-row.drag-over-before td{
        border-top:3px dashed #38bdf8;
    }

    .track-row.drag-over-after td{
        border-bottom:3px dashed #38bdf8;
    }

    .track-title{
        font-weight:bold;
    }

    .track-album{
        display:block;
        font-size:12px;
        color:#9ca3af;
        margin-top:3px;
    }

    .queue-drop-row td{
        padding:14px;
        text-align:center;
        color:#9ca3af;
        border:2px dashed #4b5563;
        border-radius:8px;
    }

    .queue-drop-row.drag-over td{
        border-color:#38bdf8;
        color:#38bdf8;
        background:rgba(56,189,248,.08);
    }

    .delete-btn{
        background:#991b1b;
        color:#fff;
        border:0;
        border-radius:5px;
        padding:5px 9px;
        cursor:pointer;
    }

    .order-output{
        margin-top:15px;
        padding:10px;
        background:#111827;
        border:1px solid #374151;
        border-radius:6px;
        font-family:Consolas, monospace;
        font-size:13px;
        color:#d1d5db;
    }

[JavaScript - Dragdrop.js]
CFFCS | CarrzSynEdit: | JS (JavaScript)
let draggedRow = null;

function getRows(){
    return Array.from(document.querySelectorAll('#trackList .track-row'));
}

function clearDropMarkers(){
    document.querySelectorAll('.drag-over-before, .drag-over-after, .drag-over').forEach(function(el){
        el.classList.remove('drag-over-before', 'drag-over-after', 'drag-over');
    });
}

function updateOrderNumbers(){
    getRows().forEach(function(row, index){
        row.children[0].textContent = index + 1;
    });
    showOrderCsv();
}

function showOrderCsv(){
    const output = document.getElementById('orderOutput');
    const csv = getRows().map(function(row, index){
        return row.dataset.trackid + ':' + (index + 1);
    }).join(',');
    output.textContent = 'OrderCsv = ' + csv;
}

function getDropPosition(row, event){
    const rect = row.getBoundingClientRect();
    const halfway = rect.top + (rect.height / 2);
    return event.clientY > halfway ? 'after' : 'before';
}

document.addEventListener('dragstart', function(event){
    const row = event.target.closest('.track-row');
    if (!row) return;

    draggedRow = row;
    event.dataTransfer.effectAllowed = 'move';
    event.dataTransfer.setData('text/plain', row.dataset.trackid || ');

    setTimeout(function(){
        row.classList.add('dragging');
    }, 0);
});

document.addEventListener('dragend', function(){
    if (draggedRow) draggedRow.classList.remove('dragging');
    draggedRow = null;
    clearDropMarkers();
});

document.addEventListener('dragover', function(event){
    const row = event.target.closest('.track-row');
    const dropzone = event.target.closest('#queue-end-dropzone');

    if (!row && !dropzone) return;

    event.preventDefault();
    clearDropMarkers();

    if (dropzone){
        dropzone.classList.add('drag-over');
        return;
    }

    if (row && row !== draggedRow){
        const pos = getDropPosition(row, event);
        row.classList.add(pos === 'after' ? 'drag-over-after' : 'drag-over-before');
    }
});

document.addEventListener('drop', function(event){
    const row = event.target.closest('.track-row');
    const dropzone = event.target.closest('#queue-end-dropzone');
    const tbody = document.getElementById('trackList');

    if (!draggedRow || (!row && !dropzone)) return;

    event.preventDefault();

    if (dropzone){
        tbody.insertBefore(draggedRow, dropzone);
    } else if (row && row !== draggedRow){
        const pos = getDropPosition(row, event);
        if (pos === 'after'){
            tbody.insertBefore(draggedRow, row.nextSibling);
        } else {
            tbody.insertBefore(draggedRow, row);
        }
    }

    clearDropMarkers();
    updateOrderNumbers();
});

document.addEventListener('click', function(event){
    const btn = event.target.closest('.delete-btn');
    if (!btn) return;

    const row = btn.closest('.track-row');
    if (row) row.remove();
    updateOrderNumbers();
});

updateOrderNumbers();