Skip to content

Instantly share code, notes, and snippets.

@vipranarayan14
Last active January 22, 2025 19:06
Show Gist options
  • Save vipranarayan14/a7fcff3fd0259dbad76916ab4f67c265 to your computer and use it in GitHub Desktop.
Save vipranarayan14/a7fcff3fd0259dbad76916ab4f67c265 to your computer and use it in GitHub Desktop.
A pure JavaScript navigable table that allows navigation using arrow keys.
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css">
</head>
<body>
<table id="navigableTable">
<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
<tr>
<td>&nbsp;</td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<script src="navigable-table.js"></script>
<script>
makeNavigable();
</script>
</body>
</html>
/**
* @param {string} tableId - Navigable table's Id.
* @param {number} activeCell - The index of the cell to be when table loads.
* @param {boolean} focus_navTable_onLoad - Focus the Navigable table when body loads.
*/
function makeNavigable(tableId = "navigableTable", activeCell = 0, focus_navTable_onLoad = true) {
var navTable = document.getElementById(tableId);
navTable.setAttribute('tabindex', -1);
navTable.addEventListener('focus', function () {
var focusedTable = document.querySelector('#' + tableId + ':focus');
if(focusedTable) {
focusedTable.style.outline = 'none';
}
});
if (focus_navTable_onLoad) {
navTable.focus();
}
var cells = navTable.querySelectorAll('tr td');
var active = activeCell;
makeCellActive();
// write 1,2,3... in the 'td's and add clickListener
for (var i = 0; i < cells.length; i++) {
if (!cells[i].innerHTML) {
cells[i].innerHTML = i;
}
cells[i].addEventListener('click', function (e) {
active = Array.prototype.indexOf.call(cells, e.target);
makeCellActive();
});
}
navTable.addEventListener('keydown', function (e) {
if (e.keyCode == 37 || 38 || 39 || 40) {
calculateActiveCell(e);
makeCellActive();
return false;
}
});
function calculateActiveCell(e) {
var rows = navTable.querySelectorAll('tr').length;
var columns = navTable.querySelectorAll('tr')[0].childElementCount;
if (e.keyCode == 37) { //move left or wrap
active = (active > 0) ? active - 1 : active;
}
if (e.keyCode == 38) { // move up
active = (active - columns >= 0) ? active - columns : active;
}
if (e.keyCode == 39) { // move right or wrap
active = (active < cells.length - 1) ? active + 1 : active;
}
if (e.keyCode == 40) { // move down
active = (active + columns <= cells.length - 1) ? active + columns : active;
}
}
function makeCellActive() {
var activeTDs = navTable.querySelectorAll('.active');
for (var i = 0; i < activeTDs.length; i++) {
activeTDs[i].classList.remove('active');
}
cells[active].classList.add('active');
}
}
td.active{
background-color:red;
color:yellow;
font-weight:bold;
}
td {
padding:5px;
text-align:center;
}
table, td {
border:1px solid black;
border-collapse: collapse;
}
@nathanstiteler
Copy link

This is working great for me all around on one table. One issue I am having is that I have multiple tables on one page behind tabbed accordions. This only seems to apply out to the table on the first tab. Any suggestions for spreading the functionality out to all of the tables?

I have tried to target other tableID, but it does not seem to apply. Another thought would be to just push this functionality to all tables?

Following up on this. Any thoughts here?

@vipranarayan14
Copy link
Author

vipranarayan14 commented Dec 20, 2024

Hi! I'm happy to hear that this is helpful to you.

This is working great for me all around on one table. One issue I am having is that I have multiple tables on one page behind tabbed accordions. This only seems to apply out to the table on the first tab. Any suggestions for spreading the functionality out to all of the tables?

If I understand your requirement correctly, tableId can be used to have more than one navigable table on a page.
I have tried it with two tables and it seems to work fine: https://jsfiddle.net/qgLuhfcw/6/

I have tried to target other tableID, but it does not seem to apply. Another thought would be to just push this functionality to all tables?

I don't quite understand the issue you are facing. Can you share your code so that I can help you better?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment