Add column sort to html table

I used a js script to convert JSON data to an HTML table at

convert json to table:

It worked fine. But now I have to add a class = "order" to table thead tr th (using JS) to sort the columns… How can I do that in plain js?

I have this: <th>Country</th>
But I need this: <th class="order">Country</th>

//Another compact but readable solution: It just requires adding the class .order to the <th> element of each column to be ordered

document.querySelectorAll('th.order').forEach(th_elem => {
 let asc=true
 const index = Array.from(th_elem.parentNode.children).indexOf(th_elem) 
 th_elem.addEventListener('click', (e) => { 
 const arr = [... th_elem.closest("table").querySelectorAll('tbody tr')]
 arr.sort( (a, b) => {
 const a_val = a.children[index].innerText
 const b_val = b.children[index].innerText 
 return (asc) ? a_val.localeCompare(b_val) : b_val.localeCompare(a_val)
 arr.forEach(elem => { 
 asc = !asc

Wern’t you using DataTables before?


let theader = document.createElement("th");


let theader = document.createElement("th");

Found a much simpler way with sortable.js as shown at:

But the problem is that I want to hide the first column from the user, but still have it accessible in js.

So, how can I hide “YT_id” column, given the sortable.js script?

 <script> // JSON DATA

data = [ 
{"YT_id":'XmU4Xyl00hY', "title":"Don't Look Back", "author":'Boston'},
{"YT_id":'9wxI4KK9ZYo', "title":'Perfect day', "author":'Lou Reed'},
{"YT_id":'XFkzRNyygfk', "title":'Creep', "author":'Radiohead'},
{"YT_id":'RQsRkDobjSs', "title":'Swallow', "author":'United Strings of Europe'},
{"YT_id":'2oT0UAoe0eQ', "title":'Slave to Love', "author":'Roxy Music'}

<script> // sortable.js
const sortable = function(data) {

 const table = document.createElement('table');
 const thead = document.createElement('thead');
 const tbody = document.createElement('tbody');
 const currentOrder = {};

 // Function to populate the tbody with the data
 const _populate = current => {
 const row = tbody.insertRow();

 row.innerHTML = Object
 .reduce((carry, key) =>
 carry + `<td>${current[key]}</td>`,

 // Create the thead from the object keys
 thead.innerHTML = '<tr>'+ 
 .reduce((carry, current) =>
 carry + `<th data-key="${current}">${current}</th>`,
 ) + 

 // Add an event listener to sort the data according
 // to the clicked th
 thead.addEventListener('click', function(event) {
 const key =;
 const sorted = currentOrder[key]
 ? data = data.sort((a, b) => a[key] < b[key] ? 1 : -1)
 : data = data.sort((a, b) => a[key] > b[key] ? 1 : -1);

 currentOrder[key] = !currentOrder[key];
 tbody.innerHTML = '';

 // Initialise and return the table

 return table;
Also I need to call a function when user clicks on an entire <tbody> <tr>. Plus I have to pass the current  <tr> <td>
values to that function.

Probably using CSS to hide all td:nth-of-type(1) by disabling their visibility.

You’ve got a reference to the row:

and an example of how to attach a click event to an element already in your code:

I shall leave it to you to put the two together. inside the function will reference the row. That element has a .children property, which refers to all the children of that node (which, for a tr, should be all of it’s associated td’s.)

It kinda works …


<script> var table = sortable(data);

 var test = document.getElementById('container');
 var rows = container.getElementsByTagName('tr');

 for (var i = 0; i < rows.length; i++) {if (i == 0) { continue;}
 rows[i].addEventListener('click', function() {
 // Do something when a row is clicked
 S0 = this.cells[0].textContent;
 S1 = this.cells[1].textContent;
 S2 = this.cells[2].textContent;
//alert (S0); alert (S1); alert (S2);

console.log('YT_id : ' + S0);
console.log('title : ' + S1);
console.log('author : ' + S2);

window.location.href = '' + S0;

User can click on any youtube video listed in the table, and it will load just fine. But t if the user clicks on the thead th to sort the column, it sorts just fine, but then subsequent clicking on a youtube video listed in the table tr does nothing!

So I need to avoid adding a js listener to the thead tr.

I played around with the for loop, but I couldn’t get in to work properly.

Can you help?

You sorter works by deleting the rows and readding them in the correct order. When it deletes the rows, it breaks the event listener. Your addEventListener should be inside the _populate function of sortable.js, after the row constant is defined in that file.

const row = tbody.insertRow();

 row.innerHTML = Object


const row = tbody.insertRow();
 row.innerHTML = Object

I couldn’t read / parse your response. So, I did it myself.

I very much appreciate your considered insight and attention to this matter.

Final product with table at page bottom: