DEV Community

Cover image for Building a Resizable and Sortable HTML Table with Ease
Sohrab zia
Sohrab zia

Posted on

32

Building a Resizable and Sortable HTML Table with Ease

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>
Enter fullscreen mode Exit fullscreen mode

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;
}

Enter fullscreen mode Exit fullscreen mode

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'));
});



Enter fullscreen mode Exit fullscreen mode

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.

Image of Timescale

Timescale – the developer's data platform for modern apps, built on PostgreSQL

Timescale Cloud is PostgreSQL optimized for speed, scale, and performance. Over 3 million IoT, AI, crypto, and dev tool apps are powered by Timescale. Try it free today! No credit card required.

Try free

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Dive into an ocean of knowledge with this thought-provoking post, revered deeply within the supportive DEV Community. Developers of all levels are welcome to join and enhance our collective intelligence.

Saying a simple "thank you" can brighten someone's day. Share your gratitude in the comments below!

On DEV, sharing ideas eases our path and fortifies our community connections. Found this helpful? Sending a quick thanks to the author can be profoundly valued.

Okay