onClick
Published on

Creating Resizable Table with Drag-Drop Reorder Functionality Using Pure JavaScript and Tailwind CSS

Authors

Resizable Table with Drag-Drop Reorder Functionality

Drag-and-drop functionality has become a standard feature in many web applications. It allows users to move elements around the page, reordering them as needed. In this tutorial, we'll explore how to create a drag-and-drop reorderable table using HTML and JavaScript.

form

Getting Started

Install Tailwind CSS

HTML Code

Creating an HTML table with some sample data:

 <table id="my-table">
    <thead>
        <!-- Resizable area -->
        <tr class="text-sm font-semibold">
            <th>Name</th>
            <th>Position</th>
            <th>Office</th>
            <th>Salary</th>
        </tr>
    </thead>
    <tbody>
        <tr class="text-sm transition-all hover:bg-gray-100">
            <td>John Doe</td>
            <td>Marketing Manager</td>
            <td>New York City</td>
            <td>$80,000</td>
        </tr>
        <tr class="text-sm transition-all hover:bg-gray-100">
            <td>Jane Smith</td>
            <td>Sales Associate</td>
            <td>Los Angeles</td>
            <td>$50,000</td>
        </tr>
        <tr class="text-sm transition-all hover:bg-gray-100">
            <td>Michael Johnson</td>
            <td>Accountant</td>
            <td>Chicago</td>
            <td>$70,000</td>
        </tr>
        <tr class="text-sm transition-all hover:bg-gray-100">
            <td>Sarah Williams</td>
            <td>Human Resources Manager</td>
            <td>Houston</td>
            <td>$90,000</td>
        </tr>
    </tbody>
</table>

JavaScript

Next, add JavaScript to make the table rows draggable and reorderable. Here's the complete code with explanation:

(function () {
    // Get the table and its rows
    var table = document.getElementById('my-table');
    var rows = table.rows;
    // Initialize the drag source element to null
    var dragSrcEl = null;

    // Loop through each row (skipping the first row which contains the table headers)
    for (var i = 1; i < rows.length; i++) {
        var row = rows[i];
        // Make each row draggable
        row.draggable = true;

        // Add an event listener for when the drag starts
        row.addEventListener('dragstart', function (e) {
            // Set the drag source element to the current row
            dragSrcEl = this;
            // Set the drag effect to "move"
            e.dataTransfer.effectAllowed = 'move';
            // Set the drag data to the outer HTML of the current row
            e.dataTransfer.setData('text/html', this.outerHTML);
            // Add a class to the current row to indicate it is being dragged
            this.classList.add('bg-gray-100');
        });

        // Add an event listener for when the drag ends
        row.addEventListener('dragend', function (e) {
            // Remove the class indicating the row is being dragged
            this.classList.remove('bg-gray-100');
            // Remove the border classes from all table rows
            table.querySelectorAll('.border-t-2', '.border-blue-300').forEach(function (el) {
                el.classList.remove('border-t-2', 'border-blue-300');
            });
        });

        // Add an event listener for when the dragged row is over another row
        row.addEventListener('dragover', function (e) {
            // Prevent the default dragover behavior
            e.preventDefault();
            // Add border classes to the current row to indicate it is a drop target
            this.classList.add('border-t-2', 'border-blue-300');
        });

        // Add an event listener for when the dragged row enters another row
        row.addEventListener('dragenter', function (e) {
            // Prevent the default dragenter behavior
            e.preventDefault();
            // Add border classes to the current row to indicate it is a drop target
            this.classList.add('border-t-2', 'border-blue-300');
        });

        // Add an event listener for when the dragged row leaves another row
        row.addEventListener('dragleave', function (e) {
            // Remove the border classes from the current row
            this.classList.remove('border-t-2', 'border-blue-300');
        });

        // Add an event listener for when the dragged row is dropped onto another row
        row.addEventListener('drop', function (e) {
            // Prevent the default drop behavior
            e.preventDefault();
            // If the drag source element is not the current row
            if (dragSrcEl != this) {
                // Get the index of the drag source element
                var sourceIndex = dragSrcEl.rowIndex;
                // Get the index of the target row
                var targetIndex = this.rowIndex;
                // If the source index is less than the target index
                if (sourceIndex < targetIndex) {
                    // Insert the drag source element after the target row
                    table.tBodies[0].insertBefore(dragSrcEl, this.nextSibling);
                } else {
                    // Insert the drag source element before the target row
                    table.tBodies[0].insertBefore(dragSrcEl, this);
                }
            }
            // Remove the border classes from all table rows
            table.querySelectorAll('.border-t-2', '.border-blue-300').forEach(function (el) {
              el.classList.remove('border-t-2', 'border-blue-300');
                });
            });
        }
})();

Let's go through each part of the code to see what it does.

Explanation

  • First, we declare three variables: table, rows, and dragSrcEl. The table variable is used to store a reference to the HTML table element with the ID of my-table. The "rows" variable is used to store a collection of all the rows in the table. Finally, the dragSrcEl variable is used to store a reference to the row that is being dragged during the drag and drop operation.

  • Next, we iterate over each row in the table starting from the second row (i.e., index 1) using a for loop. We skip the first row because it contains the table headers and should not be draggable.

  • For each row, we set the draggable attribute to true so that it can be dragged and dropped. We also attach event listeners for the dragstart, dragend, dragover, dragenter, and dragleave events.

  • The dragstart event is fired when the user starts dragging the row. In this event listener, we store a reference to the row being dragged in the dragSrcEl variable. We also set the effectAllowed property to move to indicate that the row can be moved. Finally, we set the dataTransfer property to the HTML of the row being dragged, so that it can be dropped elsewhere in the table.

  • The dragend event is fired when the drag operation ends. In this event listener, we remove the gray background color from the row and remove the blue border from any rows that were previously highlighted.

  • The dragover event is fired when the dragged element is being dragged over a valid drop target. In this event listener, we prevent the default behavior and add a blue border to the row being dragged over.

  • The dragenter event is fired when the dragged element enters a valid drop target. In this event listener, we prevent the default behavior and add a blue border to the row being entered.

  • The dragleave event is fired when the dragged element leaves a valid drop target. In this event listener, we remove the blue border from the row being left.

  • Finally, the drop event is fired when the dragged element is dropped onto a valid drop target. In this event listener, we prevent the default behavior, check that the source and target rows are different, and then insert the dragged row before or after the target row depending on its position. We then remove the blue border from any highlighted rows.

Overall, this code implements a simple drag and drop reordering functionality for an HTML table using JavaScript.

You can access the full code:

CodePen

  • avatar
    Name
    Umur Köse
    Twitter
    Twitter