HTML Table Sorting With JavaScript

Making a cool HTML table that can be sorted is a great way to make your website more fun for users. With JavaScript, you can add a sorting feature that lets people click on the headers to organize the table in different ways.

Demo HTML Table Sorting

When you click on a header in the table, the rows will be sorted based on the content of that column in ascending order. Clicking on it again will switch to descending order. included icons indicating sort direction

User Name Age Country
Joan 30 USA
Sonia 25 India
Maria Garcia 28 Spain
Bella 35 Japan

Table Sorting Function With Sort Direction Icons

An existing HTML table allows users a sorting option. Insert the following JavaScript code into your web page.

Below is the full code for sorting tables using HTML, CSS, and JavaScript. Feel free to copy and paste this code directly onto your webpage without requiring any external library code. You can even make live edits by clicking on the edit button provided

JavaScript
const tableSort = (tableId) => {
    const table = document.getElementById(tableId);
    if (!table) {
        console.error(`Table with ID "${tableId}" not found`);
        return;
    }

    const thead = table.querySelector("thead");
    const tbody = table.querySelector("tbody");
    if (!thead || !tbody) {
        console.error("Table must have <thead> and <tbody>");
        return;
    }

    const headers = thead.querySelectorAll("th");
    if (headers.length === 0) {
        console.error("No table headers found");
        return;
    }

    // Initialize sorting direction for each column
    const sortDirections = Array(headers.length).fill("asc");

    const getCellValue = (row, column) => {
        const cell = row.children[column];
        // Handle cases where cell is not found
        if (!cell) return '';
        const cellValue = cell.textContent.trim();
        return isNaN(cellValue) ? cellValue : parseFloat(cellValue);
    };

    const sortTableByColumn = (column, direction) => {
        const rows = Array.from(tbody.querySelectorAll("tr"));
        rows.sort((a, b) => {
            const cellA = getCellValue(a, column);
            const cellB = getCellValue(b, column);
            const order = direction === "asc" ? 1 : -1;
            if (typeof cellA === 'number' && typeof cellB === 'number') {
                return order * (cellA - cellB);
            } else {
                return order * cellA.toString().localeCompare(cellB);
            }
        });
        rows.forEach(row => tbody.appendChild(row));
    };

    const handleHeaderClick = (index) => {
        sortTableByColumn(index, sortDirections[index]);
        sortDirections[index] = sortDirections[index] === "asc" ? "desc" : "asc";
        updateHeaderClasses();
    };

    const updateHeaderClasses = () => {
        headers.forEach((header, index) => {
            header.classList.remove("sort-asc", "sort-desc");
            header.classList.add(sortDirections[index] === "asc" ? "sort-asc" : "sort-desc");
        });
    };

    // Attach click event listeners to each header cell
    headers.forEach((header, index) => {
        header.addEventListener("click", () => handleHeaderClick(index));
    });
};
HTML
<table class="my-table" id="sortable-table">
    <thead>
        <tr>
            <th>User Name</th>
            <th>Age</th>
            <th>Country</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>Joan</td>
            <td>30</td>
            <td>USA</td>
        </tr>
        <tr>
            <td>Sonia</td>
            <td>25</td>
            <td>India</td>
        </tr>
        <tr>
            <td>Maria Garcia</td>
            <td>28</td>
            <td>Spain</td>
        </tr>
    </tbody>
</table>
CSS
.my-table {
    border-collapse: collapse;
    width: 100%;
    font-family: Arial, Helvetica, sans-serif;
}

.my-table tr {
    background-color: #ffffff;
    color: #000;
}

.my-table th {
    padding: 10px 10px;
    border: solid 1px #ccc;
    text-align: center;
    font-size: 12px;
    font-weight: bold;
    cursor: pointer;
    user-select: none;
}

.my-table td {
    border: solid 1px #ccc;
    font-size: 13px;
    padding: 10px 10px;
    text-align: center;
}

.my-table thead>tr {
    background-color: #e9e9e9;
}

.my-table>tbody>tr:hover {
    background-color: #faffe3;
}

.my-table th::after {
    content: "";
    background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJjdXJyZW50Q29sb3IiIHZpZXdCb3g9IjAgMCAzMjAgNTEyIiAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMTM3LjQgNDEuNGMxMi41LTEyLjUgMzIuOC0xMi41IDQ1LjMgMGwxMjggMTI4YzkuMiA5LjIgMTEuOSAyMi45IDYuOSAzNC45cy0xNi42IDE5LjgtMjkuNiAxOS44SDMyYy0xMi45IDAtMjQuNi03LjgtMjkuNi0xOS44cy0yLjItMjUuNyA2LjktMzQuOWwxMjgtMTI4em0wIDQyOS4zbC0xMjgtMTI4Yy05LjItOS4yLTExLjktMjIuOS02LjktMzQuOXMxNi42LTE5LjggMjkuNi0xOS44SDI4OGMxMi45IDAgMjQuNiA3LjggMjkuNiAxOS44czIuMiAyNS43LTYuOSAzNC45bC0xMjggMTI4Yy0xMi41IDEyLjUtMzIuOCAxMi41LTQ1LjMgMHoiLz48L3N2Zz4=);
    background-repeat: no-repeat;
    width: 10px;
    height: 10px;
    display: inline-block;
    margin-left: 5px;
}

.my-table th.sort-asc::after {
    background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJjdXJyZW50Q29sb3IiIHZpZXdCb3g9IjAgMCAzMjAgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xODIuNiA0NzAuNmMtMTIuNSAxMi41LTMyLjggMTIuNS00NS4zIDBsLTEyOC0xMjhjLTkuMi05LjItMTEuOS0yMi45LTYuOS0zNC45czE2LjYtMTkuOCAyOS42LTE5LjhIMjg4YzEyLjkgMCAyNC42IDcuOCAyOS42IDE5LjhzMi4yIDI1LjctNi45IDM0LjlsLTEyOCAxMjh6Ii8+PC9zdmc+);
}

.my-table th.sort-desc::after {
    background-image: url(data:image/svg+xml;base64,PHN2ZyBmaWxsPSJjdXJyZW50Q29sb3IiIHZpZXdCb3g9IjAgMCAzMjAgNTEyIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjxwYXRoIGQ9Ik0xODIuNiA0MS40Yy0xMi41LTEyLjUtMzIuOC0xMi41LTQ1LjMgMGwtMTI4IDEyOGMtOS4yIDkuMi0xMS45IDIyLjktNi45IDM0LjlzMTYuNiAxOS44IDI5LjYgMTkuOEgyODhjMTIuOSAwIDI0LjYtNy44IDI5LjYtMTkuOHMyLjItMjUuNy02LjktMzQuOWwtMTI4LTEyOHoiLz48L3N2Zz4=);
}

Usage

JavaScript
// Initialize table sorting once the document is fully loaded
document.addEventListener('DOMContentLoaded', () => {
    tableSort("sortable-table");
});

Try it yourself edit and preview live

Edit Code