Welcome to a tutorial on how to create a simple sortable table with Javascript. So you have an array or HTML table that needs some sortable action? Sadly, there is no way we can do it with just pure HTML. We need to define data arrays and do array sorting in Javascript instead – This guide will walk you through the exact steps on how to do it, read on to find out!
TABLE OF CONTENTS
DOWNLOAD & DEMO
Here is the download link to the example code, so you don’t have to copy-paste everything.
EXAMPLE CODE DOWNLOAD
Click here to download. I have released it under the MIT license, so feel free to build on top of it or use it in your own project.
SORRY FOR THE ADS...
But someone has to pay the bills, and sponsors are paying for it. I insist on not turning Code Boxx into a "paid scripts" business, and I don't "block people with Adblock". Every little bit of support helps.
Buy Me A Coffee Code Boxx eBooks
SORTABLE TABLE ON AN EXISTING TABLE
<!-- (A) JS + CSS -->
<link rel="stylesheet" href="sortable.css">
<script src="sortable.js"></script>
<!-- (B) TABLE : NEEDS PROPER THEAD/TBODY -->
<table id="demoA">
<thead>
<tr>
<td>Fruit</td>
<td>Color</td>
</tr>
</thead>
<tbody>
<tr>
<td>Durian</td>
<td>Green</td>
</tr>
<tr>
<td>Orange</td>
<td>Orange</td>
</tr>
<tr>
<td>Apple</td>
<td>Red</td>
</tr>
<tr>
<td>Grape</td>
<td>Red</td>
</tr>
<tr>
<td>Blueberry</td>
<td>Blue</td>
</tr>
<tr>
<td>Pear</td>
<td>Green</td>
</tr>
</tbody>
</table>
<!-- (C) INITIALIZE -->
<script>
sortable(document.getElementById("demoA"));
</script>
Fruit | Color |
Durian | Green |
Orange | Orange |
Apple | Red |
Grape | Red |
Blueberry | Blue |
Pear | Green |
- Load the Javascript
sortable.js
, the CSS is optional. - Create your HTML table as usual. Just make sure that it has a proper
<thead>
and<tbody>
section. - Call
sortable(HTML TABLE)
to turn it into a sortable table.
SORTABLE TABLE WITH OBJECT DATA
<!-- (B) EMPTY TABLE -->
<table id="demoB"></table>
<!-- (C) INITIALIZE -->
<script>
sortable(document.getElementById("demoB"), {
ID : [44, 11, 7, 5, 2],
Name : ["John Doe", "Jane Doe", "Aaron Doe", "Zoe Doe", "Derrick Doe"],
Color : ["Red", "Green", "Blue", "White", "Red"]
});
</script>
Yes, it’s the same sortable()
, except that we pass in an object data in the second parameter.
P.S. The object must be in the format of { HEAD : [ROWS], HEAD : [ROWS], ETC... }
SORTABLE TABLE JAVASCRIPT
With that, let us now get into more details of how the sortable table work in this section – This is for you guys who want to “deep customize” it.
TUTORIAL VIDEO
PART 1) ADDING FLAGS TO THE TABLE
function sortable (instance, data) {
// (A) FLAGS
instance.sBy = null; // sort by this column
instance.sDirection = true; // ascending/descending order
instance.sOrder = []; // calculated sort order
// ...
}
The entire Javascript file only has a function sortable()
, which you have seen in the above demo. A quick reminder on the parameters:
instance
The HTML table itself.data
Optional, object data.
The first thing we do is to initialize the sort mechanics by adding flags to the HTML table. Yes, beginners, we can add variables to HTML elements in modern Javascript.
sBy
Sort by which column.sDirection
Sort in ascending (true
) or descending (false
) order.sOrder
The calculated sort order.
PART 2) SORT FUNCTION
// (B) SORT FUNCTION
instance.sort = selected => {
// (B1) UPDATE SORT FLAGS
if (instance.sBy == selected.innerHTML) {
instance.sDirection = !instance.sDirection;
} else {
instance.sBy = selected.innerHTML;
instance.sDirection = true;
}
// (B2) UPDATE CSS OF HEADER CELLS
for (let c of instance.head.rows[0].cells) {
c.classList.remove("sortup");
c.classList.remove("sortdown");
if (c == selected) {
c.classList.add((instance.sDirection ? "sortup" : "sortdown"));
}
}
// (B3) MAP OUT DATA OF THE SELECTED COLUMN
// I.E. WE NEED TO RETAIN THE INDEX POSITIONS WHILE SORTING
let map = data[selected.innerHTML].map((v, i) => { return { i: i, v: v }; });
// (B4) SORT ARRAY
if (instance.sDirection) {
map.sort((a, b) => {
if (a.v > b.v) { return 1; }
if (a.v < b.v) { return -1; }
return 0;
});
} else {
map.sort((a, b) => {
if (a.v < b.v) { return 1; }
if (a.v > b.v) { return -1; }
return 0;
});
}
// (B5) REDRAW TABLE WITH NEW SORT ORDER
instance.sOrder = [];
for (let idx in map) { instance.sOrder.push(map[idx].i); }
delete(map); instance.draw();
};
Yikes, the next piece of confusion is called “sort”. Not going to explain this line-by-line, but the essentials are:
- As above. Keep in mind that the table
data
is kept in the format of{ HEAD : [ITEM, ITEM, ITEM] }
. - We will not mess with
data
directly, but calculate the sort order for[ITEM, ITEM, ITEM]
separately insOrder
. - When the user clicks on a header cell to sort:
- (B1) We set the “sort by this column”
sBy
and sort directionsDirection
. - (B3) Create a temporary
var map
with both the index and value of the items –var map = [{i:INDEX, v:ITEM}, {i:INDEX, v:ITEM}]
. - (B4) Sort the
map
. - (B5) Loop through
map
, extract only the index intosOrder
.
- (B1) We set the “sort by this column”
PART 3) DRAW TABLE ROWS
// (C) DRAW HTML TABLE
instance.draw = () => {
// (C1) REMOVE OLD SORT ORDER
instance.body.innerHTML = "";
// (C2) DRAW NEW SORT ORDER
let r, c;
for (let i of instance.sOrder) {
r = instance.body.insertRow();
for (let key in data) {
c = r.insertCell();
c.innerHTML = data[key][i];
}
}
};
Once we have the sort order, simply loop through sOrder
and draw the table rows.
PART 4) READ EXISTING TABLE
// (D) ADAPT DATA FROM EXISTING TABLE
if (data==undefined) {
// (D1) GET TABLE SECTIONS
instance.head = instance.querySelector("thead");
instance.body = instance.querySelector("tbody");
// (D2) GET DATA FROM HEADER
data = {}; keys = [];
for (let c of instance.head.rows[0].cells) {
data[c.innerHTML] = [];
keys.push(c.innerHTML);
}
// (D3) GET DATA FROM BODY
for (let r of instance.body.rows) { for (let i=0; i<r.cells.length; i++) {
data[keys[i]].push(r.cells[i].innerHTML);
}}
delete(keys);
}
Remember the data
parameter? For existing tables, we simply run through the table and adapt the data
.
PART 5) BUILD SORTABLE TABLE FROM OBJECT
// (E) DRAW SORTABLE TABLE FROM OBJECT
else {
// (E1) CREATE TABLE SECTIONS
instance.head = instance.createTHead();
instance.body = instance.createTBody();
// (E2) HEADER CELLS
let r = instance.head.insertRow();
r = instance.head.rows[0];
for (let key in data) {
let c = r.insertCell();
c.innerHTML = key;
}
// (E3) DEFAULT SORT ORDER & DRAW BODY
for (let i=0; i<data[Object.keys(data)[0]].length; i++) { instance.sOrder.push(i); }
instance.draw();
}
If an object data
is specified, we simply build the HTML from it.
PART 6) CSS CLASS & CLICK TO SORT
// (F) CLICK ON HEADER CELL TO SORT
instance.classList.add("sorta");
for (let r of instance.head.rows) { for (let c of r.cells) {
c.onclick = () => instance.sort(c);
}}
This final part should be self-explanatory. We attach the “click to sort” on all header cells.
EXTRAS
That’s all for this project, and here is a small section on some extras and links that may be useful to you.
LIMITATIONS & PERFORMANCE
This sortable table relies on ARRAY.sort()
– It should work pretty well and fast with most modern computers these days… But yep, it is not the most effective way to do sorting, and you will probably get hit with performance issues with large datasets.
NO “ERROR CHECKING”
Please make sure that your dataset and number of columns are correct on your own. I have contemplated adding an “auto check and fix”, but came to a simple conclusion:
- Checking massive datasets takes resources, it is simply not efficient to do so for the sake of “dummy proofing”.
- This is a “simple sortable table” tutorial, not “how to automatically fix your screw-up”.
- As a developer (or even as a user), you are responsible for the integrity of your own datasets.
- If there is a missing column or extra columns – Only you know what needs to be fixed.
COMPATIBILITY CHECKS
- Arrow Function – CanIUse
- Query Selector – CanIUse
All the required features are well-supported on modern browsers.
LINKS & REFERENCES
- Javascript Array Sort – MDN
- Javascript Array Reverse Sort – MDN
- Array Map – MDN
THE END
Thank you for reading, and we have come to the end of this guide. I hope that it has helped you with your project, and if you want to share anything with this guide, please feel free to comment below. Good luck and happy coding!
Hello, I am JS enthusiast but not a pro.
Well done but it crash when more column in bodythat in header (well ok that’s not supposed to be). Correction to allow more body column that header 🙂
Thanks for sharing. I will assume you mean “when the number of columns in the head and body doesn’t match”. I will add a check and throw errors in the future, but not “automatically fix it” by generating empty cells – Users should verify the data by themselves.
This is a very useful Javascript code. Thanks. I edited this code. Because sorting numbers is not really working on HTML table dom. Please check this: https://atakanau.blogspot.com/2020/12/sortable-table-using-pure-javascript.html