CSS tables with sortable columns using TinySort

Try searching for “CSS table sortable columns”. Good luck. Most of the sortable table libraries require that your data be in an HTML table. But you lose a lot of responsive flexibility when you use HTML tables. This presents you with a lousy choice: sortable columns and limited responsive design options, or responsive design options, and no sortable columns. I’m sure there are complex solutions to this which would involve sending different content based on browser or resolution detection, but that’s sounds like a maintenance nightmare.

Fortunately, there’s TinySort. TinySort will sort any HTML element, so it’s not bound to just the classic TABLE>TR>TD structure. And although it’s not very clear that it’s possible from the documentation, the sorting tables example shows that you can specify any elements as the source of rows and cells.

Working from the sample code, I was able to make sortable columns on a CSS-only table. Clicking on any of the column heads will sort that column, and re-order the other columns at the same time:

User Likes Replies Top Answers Top Topic
Bob Smith
5
2
2
Sally Jones
4
1
1
Sam Hill
4
2
1
Wendy Brown
3
2
1
Ed Green
3
3
2
Lucy Edwards
2
1
1
Gary Waters
2
4
2
Rita O’Brien
1
2
1
William Lander
1
1
1

 

Here’s the HTML:

<div class="user_leaderboard" id="userleaderboard">
	<span class="table_head">
		<span class="table_label">User</span>
		<span class="table_label">Likes</span>
		<span class="table_label">Replies</span>
		<span class="table_label">Top Answers</span>
		<span class="table_label">Top Topic</span>
	</span>
	<span class="table_body">
	    <div class="table_row">
	        <div class="table_cell">Bob Smith</div>
	        <div class="table_cell">5</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #AB9364;">Sales</span></a></div>
	    </div>     
	    <div class="table_row">
	        <div class="table_cell">Sally Jones</div>
	        <div class="table_cell">4</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #50BEFF;">Accounting</span></a></div>
	    </div> 
	    <div class="table_row">
	        <div class="table_cell">Sam Hill</div>
	        <div class="table_cell">4</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #50BEFF;">Accounting</span></a></div>
	    </div>     
	    <div class="table_row">
	        <div class="table_cell">Wendy Brown</div>
	        <div class="table_cell">3</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #B00400;">Procurement</span></a></div>
	    </div> 
	    <div class="table_row">
	        <div class="table_cell">Ed Green</div>
	        <div class="table_cell">3</div>
	        <div class="table_cell">3</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #50BEFF;">Marketing</span></a></div>
	    </div>     
	    <div class="table_row">
	        <div class="table_cell">Lucy Edwards</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #FF8400;">Marketing</span></a></div>
	    </div> 
	    <div class="table_row">
	        <div class="table_cell">Gary Waters</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">4</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #EC00D9;">Accounting</span></a></div>
	    </div> 
	    <div class="table_row">
	        <div class="table_cell">Rita O'Brien</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell">2</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #50BEFF;">Leasing</span></a></div>
	    </div>     
	    <div class="table_row">
	        <div class="table_cell">William Lander</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell">1</div>
	        <div class="table_cell"><a class="table_link" style="color: #FFFFFF"><span class="table_cellblock" style="color: #FFFFFF; background-color: #50BEFF;">Leasing</span></a></div>
	    </div>
	</span>
</div>

You will need to include the TinySort library, preferably in your <head> section:

<script type='text/javascript' src='//cdnjs.cloudflare.com/ajax/libs/tinysort/2.2.2/tinysort.js'></script>

Here’s the CSS:

.user_leaderboard {
	display: table;
	width: 80%;
	border: 1px solid #ccc;
	font-family: arial,helvetica,sans-serif;
}
.table_head {
	display: table-header-group;
	background-color: #eee;
}
.table_label {
	display: table-cell;
	font-weight: bold;
	border-bottom: 2px solid #ccc;		
	padding: 3px;
}
.table_body {
	display: table-row-group;
	background-color: #fff;
}
.table_row {
	display: table-row;
	line-height: 20px;
}
.table_cell {
	display: table-cell;
	padding: 2px 3px;
}
.table_cellblock {
	padding: 2px 3px;
}

And here’s the TinySort JS. Make sure this is called after the HTML, or else you’ll get ‘can’t get properties of null’ errors:

var table = document.getElementById('userleaderboard')
	,tableHead = table.querySelector('span.table_head')
	,tableHeaders = tableHead.querySelectorAll('span.table_label')
	,tableBody = table.querySelector('span.table_body')
;
tableHead.addEventListener('click',function(e){
	var tableHeader = e.target
		,textContent = tableHeader.textContent
		,tableHeaderIndex,isAscending,order
	;
	if (textContent!=='add row') {
		// Note: the value in the tableHeader.nodeName check must be UPPERCASE
		while (tableHeader.nodeName!=='SPAN') {
			tableHeader = tableHeader.parentNode;
		}
		tableHeaderIndex = Array.prototype.indexOf.call(tableHeaders,tableHeader);
		isAscending = tableHeader.getAttribute('data-order')==='asc';
		order = isAscending?'desc':'asc';
		tableHeader.setAttribute('data-order',order);
		tinysort(
			tableBody.querySelectorAll('div.table_row')
			,{
				selector:'div.table_cell:nth-child('+(tableHeaderIndex+1)+')'
				,order: order
			}
		);
	}
});

Leave a Reply

Your email address will not be published. Required fields are marked *