Using Navigation keys to Move Through an HTML Table

by Jon Wojtowicz

A common question I come across is how to allow the user to navigate between rows in an HTML table using the arrow keys. This was a requirement I had for a web based data entry application I was working on several years ago. The solution I used worked well but I'll be the first to admit it is not the only solution, it is one solution.



Allowing focus on elements
The biggest issue with trying to tab key through a table is that the table rows and cells cannot receive focus. Since these elements cannot receive focus, they cannot receive key presses for the arrow keys as well. My solution was to use an element that could receive focus. In my case I used an input element of type text. I embedded a textbox into each row of the table as the target of the focus. Since I didn't want this showing in my grid I had to hide the textbox. Changing its type to hidden or setting its display style to any non-visible style will prevent it from receiving focus. My solution was to place this control in the first cell of the row with a cell width of 0. This allowed it to receive focus and prevented the user from seeing it.
The next step was capturing the key presses I was interested in. These were the tab, arrow down, arrow up, back key and enter. The enter key was used the same as the row click to make the selection. The resultant HTML looked similar to the following for each row.
 
				<tr class="cell" 
				colorid="White" id="10273" onclick="selectRow(this)"> <td 
				width="0px"><input type="text" style="width:0px;" onfocus="Hilight(this)" 
				onblur="unHilight(this)" onkeydown="keyRow(this,'selectRow')" ID="Text1" 
				NAME="Text1"></td> <td width="150px">10273</td> <td 
				width="150px">08/05/1996</td> <td 
				width="150px">09/02/1996</td> <td 
				width="150px">08/12/1996</td> </tr> 
Client Script
Now that the framework was setup to get focus on each row, I had to create the client function that would make this magic happen.
I started with the selectRow method as this was the easiest. This was simply capturing te currently selected id and submitting the form for processing.
 
function selectRow(oRow) { document.all.hdnOrderHeaderId.value = oRow.id; document.all.frmOrderInfo.submit(); }			
			
The next methods were the Hilight and unHilight. Both of these methods had an argument of the textbox that fired them. This was simply changing the background color of the newly selected row and reverting the color of the previously selected row.
 
function Hilight(oSrc)
{
	oSrc.parentElement.parentElement.bgColor = "MediumSeaGreen";
	oSrc.parentElement.parentElement.scrollIntoView(false);
}

function unHilight(oSrc)
{
	oSrc.parentElement.parentElement.bgColor = oSrc.parentElement.parentElement.getAttribute("colorid");
}

The last method that needed to be created was to handle the key press. This method simply checked the key that was presses and reacted to the keys of interest. It also took in the textbox that triggered the event and the name of the method to execute on an enter.
 
function keyRow(oSrc, oFn)
{
	if(window.event.keyCode == 13)
	{
		eval(oFn + "(oSrc.parentElement.parentElement)");
	}
	if(window.event.keyCode == 40)
	{
		if(oSrc.parentElement.parentElement.rowIndex == oSrc.parentElement.parentElement.parentElement.rows.length - 1)
			return;
		else
		{
			oSrc.parentElement.parentElement.parentElement.rows[oSrc.parentElement.parentElement.rowIndex + 1].cells[0].children[0].focus();
			return;
		}
	}
	if(window.event.keyCode == 38)
	{
		if(oSrc.parentElement.parentElement.rowIndex == 0)
			return;
		else
		{
			oSrc.parentElement.parentElement.parentElement.rows[oSrc.parentElement.parentElement.rowIndex - 1].cells[0].children[0].focus();
			return;
		}
	}
}
			
			
Final Result
One last item that was needed was to set the focus on the first row when the page loaded. If the user selected a row using a click, the page would submit so this step is essential. The steps to perform this was to create another method and attach it to the onload event.
 
function pageLoad() { if (document.all.tblOrder.rows.length > 0) document.all.tblOrder.rows[0].cells[0].children[0].focus(); }
			

I've included a sample ASP.Net application that uses the explained method. It uses the Northwind SQL database as a data source. The connection string may have to be modified depending on your particular data source.

Download the code sample that accompanies this article

Jon Wojtowicz is a C# MVP and a Systems Analyst at a large insurance company in Chattanooga, TN where he currently provides developer support and internal training. He has worked as a consultant working with Microsoft Technologies. This includes ASP, COM, VB6 and .Net, both C# and VB.Net since Beta 1. He has been an MCSD since 1999 and an MCT since 2000. Prior to getting a degree in Computer science he worked as a process engineer focusing on process automation, programmable controllers and equipment installations. In his spare time he likes woodworking and gardening.
Article Discussion: