Building a Resizable and Sortable HTML Table with Ease
Tags: codepen, html, javascript, table
Published: 2023-12-06 05:18:05

Are you tired of static, non-flexible tables that refuse to adapt to your needs? In this tutorial, we'll explore how to transform a standard HTML table into a dynamic and user-friendly powerhouse using a combination of HTML, CSS, and JavaScript.

## The Setup

Let's begin with the HTML structure. We have a simple table containing some data about individuals:

```
<div class="container mt-3">
  <table id="resizeMe" class="resizable-table table table-hover">
    <thead>
       <tr id="header-row">
        <th class="draggable-table" data-column="0">No.</th>
        <th class="draggable-table" data-column="1">First name</th>
        <th class="draggable-table" data-column="2">Last name</th>
      </tr>
    </thead>
    <tbody>
      <tr>
        <td>1</td>
        <td>Andrea</td>
        <td>Ross</td>
      </tr>
      <tr>
        <td>2</td>
        <td>Penelope</td>
        <td>Mills</td>
      </tr>
      <tr>
        <td>3</td>
        <td>Sarah</td>
        <td>Grant</td>
      </tr>
      <tr>
        <td>4</td>
        <td>Vanessa</td>
        <td>Roberts</td>
      </tr>
      <tr>
        <td>5</td>
        <td>Oliver</td>
        <td>Alsop</td>
      </tr>
      <tr>
        <td>6</td>
        <td>Jennifer</td>
        <td>Forsyth</td>
      </tr>
      <tr>
        <td>7</td>
        <td>Michelle</td>
        <td>King</td>
      </tr>
      <tr>
        <td>8</td>
        <td>Steven</td>
        <td>Kelly</td>
      </tr>
      <tr>
        <td>9</td>
        <td>Julian</td>
        <td>Ferguson</td>
      </tr>
      <tr>
        <td>10</td>
        <td>Chloe</td>
        <td>Ince</td>
      </tr>
    </tbody>
  </table>
</div>
```

And the accompanying CSS to style our table:

```
.table {
  border-collapse: collapse;
  width: 100%;
}

.table,
.table th,
.table td {
  border: 1px solid #ccc;
}

.table th,
.table td {
  padding: 0.5rem;
}

.table th {
  position: relative;
   cursor: grab;
      user-select: none;
}   
   .table th:active {
      cursor: grabbing;
    }

.resizer {
  position: absolute;
  top: 0;
  right: 0;
  width: 5px;
  cursor: col-resize;
  user-select: none;
}

.resizer:hover,
.resizing {
  border-right: 2px solid blue;
}

.dragging {
  background-color: #f0f0f0;
}

```

## The Magic of JavaScript

Now, the real magic happens when we inject JavaScript into the mix. We're using two different approaches here: one with the fantastic interact.js library for dragging and resizing columns and another using a custom implementation.

```
document.addEventListener('DOMContentLoaded', function () {
  const makeTableResizableAndSortable = function (table) {
    const tableBody = table.querySelector('tbody');

    // Make rows sortable
    const rowsSortable = new Sortable(tableBody, {
      animation: 150,
    });

    // Make columns and table header cells draggable using interact.js
    const headers = table.querySelectorAll('th');
    interact(headers).draggable({
      // Enable both left and right edges for dragging
      edges: { left: true, right: true, bottom: false, top: false },
      listeners: {
        start(event) {
          const target = event.target;
          target.classList.add('dragging');
        },
        move(event) {
          const target = event.target;
          const dx = event.dx;
          target.style.transform = `translate(${dx}px)`;
        },
        end(event) {
          const target = event.target;
          target.style.transform = '';
          target.classList.remove('dragging');
        },
      },
    }).resizable({
      // Enable right edge for resizing
      edges: { right: true },
      restrictEdges: {
        outer: 'parent',
      },
      restrictSize: {
        min: { width: 50 },
      },
      listeners: {
        move(event) {
          const target = event.target;
          const width = parseFloat(target.style.width) || 0;
          target.style.width = width + event.dx + 'px';
        },
      },
    });
  };

  const tables = document.querySelectorAll('.resizable-table');
  tables.forEach(function (table) {
    makeTableResizableAndSortable(table);
  });
});



document.addEventListener('DOMContentLoaded', function () {
const createResizableTable = function (table) {
const cols = table.querySelectorAll('th');
[].forEach.call(cols, function (col) {
// Add a resizer element to the column
const resizer = document.createElement('div');
resizer.classList.add('resizer');


// Set the height
resizer.style.height = `${table.offsetHeight}px`;


col.appendChild(resizer);


createResizableColumn(col, resizer);
});
};


const createResizableColumn = function (col, resizer) {
let x = 0;
let w = 0;


const mouseDownHandler = function (e) {
x = e.clientX;


const styles = window.getComputedStyle(col);
w = parseInt(styles.width, 10);


document.addEventListener('mousemove', mouseMoveHandler);
document.addEventListener('mouseup', mouseUpHandler);


resizer.classList.add('resizing');
};


const mouseMoveHandler = function (e) {
const dx = e.clientX - x;
col.style.width = `${w + dx}px`;
};


const mouseUpHandler = function () {
resizer.classList.remove('resizing');
document.removeEventListener('mousemove', mouseMoveHandler);
document.removeEventListener('mouseup', mouseUpHandler);
};


resizer.addEventListener('mousedown', mouseDownHandler);
};


createResizableTable(document.getElementById('resizeMe'));
});



```

## How It Works

- Sorting Rows
The rows become sortable with the help of the Sortable library, allowing you to effortlessly rearrange your data.

- Dragging Columns
Thanks to interact.js, column headers become draggable. A simple visual transformation occurs while dragging, making the experience intuitive.

- Resizing Columns
Resizing columns is made easy by placing a resizer at the right edge of each column. A smooth resizing effect is achieved with the interact.js library.

## Wrapping Up

And there you have it! A brief yet powerful guide on creating a resizable and sortable HTML table. Whether you prefer the simplicity of interact.js or a custom implementation, the end result is a table that bends to your will.


{% codepen https://codepen.io/sohrabzia/pen/ZEwoaVx %}