Skip to Content

jQuery Table Sorting: Sort Data on Header Click

In this tutorial, we'll discuss table sorting with jQuery. We'll create a few functions that will sort table data on header click without the use of any additional plugins or bloated code. Let's get started!

The Table Data

Let's put together an HTML table containing some user IDs, a first name, and a last name:

<table>
<caption>Users</caption>

<thead>
<tr>
<th>ID</th>
<th>First Name</th>
<th>Last Name</th>
<th class="no-sort"></th>
</tr>
</thead>

<tbody>
<tr>
<td>1</td>
<td>Luke</td>
<td>Skywalker</td>
<td>X</td>
</tr>
<tr>
<td>2</td>
<td>Leia</td>
<td>Organa</td>
<td>X</td>
</tr>
<tr>
<td>3</td>
<td>Anakin</td>
<td>Skywalker</td>
<td>X</td>
</tr>
</tbody>
</table>

Notice that we've separated our table headings from the data in the body. This is crucial to ensure that, when sorting data, the table headings don't get sorted inadvertently. You could also do the same with the table footer by using a tfoot for separation.

The Table Sort Click Event

Now that we have our table data, let's get right into the jQuery table sorting code.

We need to create a click event to the table headers, excluding any columns with the no-sort class:

$(document).on("click", "table thead tr th:not(.no-sort)", function() {
let table = $(this).parents("table");
let rows = $(this).parents("table").find("tbody tr").toArray().sort(TableComparer($(this).index()));
let dir = ($(this).hasClass("sort-asc")) ? "desc" : "asc";

if (dir == "desc") {
rows = rows.reverse();
}

for (let i = 0; i < rows.length; i++) {
table.append(rows[i]);
}

table.find("thead tr th").removeClass("sort-asc").removeClass("sort-desc");
$(this).removeClass("sort-asc").removeClass("sort-desc") .addClass("sort-" + dir);
});

In this function, we first identify the table and the data rows so we don't have to make extra calls to the DOM.

Next, we identify the sort direction. If the table heading has a class of sort-asc, then descending sort is assumed. Otherwise, we will sort our data numerically or alphabetically in ascending format.

If the sort direction is descending, then we reverse the table rows with rows.reverse().

Next, we loop through each table row and append to the table so they're sorted in the desired manner.

The last part does some class changes so clicking on the table heading multiple times will allow for different directional sorting. It also determines whether an up or down arrow is displayed in the table heading, illustrating the sort direction to the user.

Table Row Comparisons

The TableComparer() function call in our click event function is where the sorting magic happens. This function compares each table cell value with the surrounding values and sorts accordingly:

function TableComparer(index) {
return function (a, b) {
let val_a = TableCellValue(a, index).replace(/\$\,/g, "");
let val_b = TableCellValue(b, index).replace(/\$\,/g, "");
let result = val_a.toString().localeCompare(val_b);

if ($.isNumeric(val_a) && $.isNumeric(val_b)) {
result = val_a - val_b;
}

if (isDate(val_a) && isDate(val_b)) {
let date_a = new Date(val_a);
let date_b = new Date(val_b);
result = date_a - date_b;
}

return result;
}
}

Here, we first check for string comparisons. Then, we check if the value is numeric and run a numeric comparison. Finally, we do a date validation against the string and sort accordingly, if needed.

And the TableCellValue() that it's related to does exactly what it sounds like. It returns the value of the table cell:

function TableCellValue(row, index) {
return $(row).children("td").eq(index).text();
}

Date Validation

The isDate() function confirms whether or not the received value is a valid date string:

function isDate(val) {
let d = new Date(val);

return !isNaN(d.valueOf());
}

CSS Explanation

You can style the table any way you would like. But there are a few notable items to consider like displaying the sort arrow in the table heading, either up or down depending on the current sort direction of the selected column.

Here is the CSS that displays the arrows as needed:

table thead tr th:after {
position: absolute;
right: 2px;
}

table thead tr th.sort-asc:after {
content: "\25b4";
}

table thead tr th.sort-desc:after {
content: "\25be";
}

The first rule adds absolute positioning for the arrow on the right side of the table heading while the remaining two rules actually display the arrow in the table heading.

The jQuery table sorting click event function that we went over above is where the sort class is determined.

Conclusion

I've seen many examples and plugins over the years that are extremely complicated, bloated, and even unnecessary. This example takes the idea of table sorting with jQuery and simplifies it in a way that's easy to understand and keeps your code minimal.

You can download the full example on my GitHub. Enjoy!

Last Updated: March 29, 2024
Created: September 16, 2021