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.
Top comments (0)