JSFiddle - React, Tailwind, and code Playground
by Imri Paloja
JavaScript
/**
* Sort HTML table by column index
* @param {string} tableClass - class name of the table
* @param {number} colIndex - column index to sort by (0-based)
*/
function sortTable(tableClass, colIndex) {
const table = document.querySelector(`.${tableClass}`);
if (!table) return;
const tbody = table.tBodies[0];
const rows = Array.from(tbody.rows);
// Get current sort direction from data attribute (or default to asc)
const header = table.querySelectorAll('th')[colIndex];
const currentDir = header?.dataset.sortDir || 'asc';
const direction = currentDir === 'asc' ? 'desc' : 'asc';
// Clean previous sort indicators
table.querySelectorAll('th').forEach((th) => {
th.dataset.sortDir = '';
th.classList.remove('sort-asc', 'sort-desc');
});
// Set new direction
if (header) {
header.dataset.sortDir = direction;
header.classList.add(direction === 'asc' ? 'sort-asc' : 'sort-desc');
}
// Natural compare function (handles numbers, strings, dashes, etc.)
rows.sort((a, b) => {
let x = getCellValue(a, colIndex);
let y = getCellValue(b, colIndex);
// Handle special dash case
if (x === '-' && y !== '-') return direction === 'asc' ? -1 : 1;
if (y === '-' && x !== '-') return direction === 'asc' ? 1 : -1;
if (x === '-' && y === '-') return 0;
// Natural compare
return naturalCompare(x, y) * (direction === 'asc' ? 1 : -1);
});
// Re-attach rows in new order (very efficient)
rows.forEach((row) => tbody.appendChild(row));
}
// Extract clean value from cell
function getCellValue(row, index) {
const cell = row.cells[index];
if (!cell) return '';
let text = cell.textContent || cell.innerText || '';
// Remove extra spaces
text = text.trim();
// Handle common special cases
if (text === '-' || text === '—' || text === '–') return '-';
if (text === '' || text === 'N/A' || text === 'n/a') return '';
// Try to convert to...