How Do I Make a Full Table Row Clickable Using jQuery?

Back in 2004, I wrote an article about making a full table row clickable using JavaScript, so you could click anywhere in the table row to browse to a new page. That solution used quite a bit of in-line JavaScript to accomplish that task which adds to the size and complexity of the page. Since then, the JavaScript landscape has changed quite a bit with the introduction of JavaScript libraries such as Prototype and jQuery. Because my initial article is in the top 10 results for "full row select javascript" on Google, I figured it made sense to write a new, cleaner and more modern version of it using one of those libraries: jQuery.

Full Clickable Table Rows the jQuery Way

What I really like about jQuery is its unobtrusive nature. Using jQuery, it's very easy to completely separate your markup from the JavaScript code, something that's a lot harder to accomplish without it. This enables you to have clean markup and define your logic elsewhere in a script block or separate script file. This in turn makes it easy to create a page that looks good in modern browsers as well as in those that don't support JavaScript or don't have it turned on.

I'll show you the full code first, and then discuss some of its important parts afterward. You can try out a demo of the page here.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" 
               "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <title>Full Row Select Using jQuery</title>
  <script src="Scripts/jquery-1.4.2.min.js" type="text/javascript"></script>
  <style type="text/css">
    .Highlight
    {
      background-color: #dcfac9;
      cursor: pointer;
    }
  </style>
</head>
<body>
  <table width="100%" border="1" cellpadding="0" cellspacing="0" id="link-table">
  <tr>
    <td><a href="http://www.yahoo.com/">http://www.yahoo.com/</a></td>
    <td>1</td>
    <td>2</td>
    <td>3</td>
  </tr>
  <tr>
    <td><a href="http://www.microsoft.com/">http://www.microsoft.com/</a></td>
    <td>4</td>
    <td>5</td>
    <td>6</td>
  </tr>
  <tr>
    <td><a href="http://imar.spaanjaars.com/">http://imar.spaanjaars.com/</a></td>
    <td>7</td>
    <td>8</td>
    <td>9</td>
  </tr>
  </table>
  <script type="text/javascript">
    $(function ()
    {
      // Hide the first cell for JavaScript enabled browsers.
      $('#link-table td:first-child').hide();

      // Apply a class on mouse over and remove it on mouse out.
      $('#link-table tr').hover(function ()
      {
        $(this).toggleClass('Highlight');
      });
  
      // Assign a click handler that grabs the URL 
      // from the first cell and redirects the user.
      $('#link-table tr').click(function ()
      {
        location.href = $(this).find('td a').attr('href');
      });
    });
  </script>
</body>
</html>    

I am using pretty much the same HTML as in my initial article, with a few exceptions. First, notice the inclusion of the id attribute on the <table> element. This makes it easier to address the table from jQuery code. Secondly, I removed the onmouseover, onmouseout and onclick attributes from the table row. As you'll see in a bit, this is now all handled by jQuery. Finally, I added a new table cell containing an <a> element with the URL I want to link the row to. The jQuery code will hide that cell giving you the same table as in the initial article, shown in Figure 1 that displays the page while the mouse is over the first row:


Figure 1 (click to enlarge)

However, browsers that don't support JavaScript now see the table shown in Figure 2:


Figure 2 (click to enlarge)

As you can see, the links are now visible and clickable, resulting in a nice fall back scenario for browsers that don't handle JavaScript.

The next interesting piece of code to look at is the JavaScript block at the end. This code sets up jQuery's document ready function using $(function () { ... }); which fires when the browser is done loading the document. The first line of that code hides the first cell of each table row; effectively hiding the link that each cell contains:

$('#link-table td:first-child').hide();

This code first gets a reference to the table (using #link-table) and then to each "first child" of each table row (using td:first-child). It then hides these table cells using hide(). For more information about first-child, check out the jQuery documentation. Once this code is finished executing, the table looks the same as in the initial article.

The next piece of code assigns a handler to the hover function which fires when you move your mouse over the selected element. You can set up hover with two functions (which trigger on mouse over and on mouse out respectively), or with just a single one as I have done in this example. This causes the same piece of code to be called when you mouse over and mouse out again. Since I am using toggleClass (which adds a CSS class to the selected elements when it's not present and removes it when it is), this is very convenient:

$('#link-table tr').hover(function ()
{
  $(this).toggleClass('Highlight');
});      

In both cases, toggleClass('Highlight') is called, adding and removing the CSS class Highlight (defined at the top of the document) as you hover over the rows. Besides changing the background color of the table row, this class also changes the cursor into a hand icon, making it more obvious you can click the row. You can see how this behaves in the live demo.

The final piece of code (and the most important one) is the part that assigns a click handler to each row, taking the user to the URL defined in the <a> element in the first (and now hidden) table cell:

$('#link-table tr').click(function ()
{
  location.href = $(this).find('td a').attr('href');
});      

The this reference in this piece of code refers to the selected table row. By wrapping it in $() you end up with another jQuery matched set which in turn exposes a handy find method that lets you search for specific elements: all <a> elements in my case. The attr method then in turn returns the href property of the first element in the matched set. Since there's only one <a> element in each table row, that's exactly what I want. The returned href is then assigned to location.href, which causes the browser to request that page.

The final page is now a lot cleaner than the one from my initial article as it no longer contains in-line JavaScript in the markup. Additionally, it's now a lot easier to move the JavaScript code to a separate file, enabling reuse and a potential performance improvement. Finally, the code now gracefully degrades for browsers that don't support JavaScript by providing similar functionality. Although for those users the page doesn't look as good as the jQuery enabled one, they can still navigate to the URLs defined in the links.


Where to Next?

Wonder where to go next? You can read existing comments below or you can post a comment yourself on this article .


Consider making a donation
Please consider making a donation using PayPal. Your donation helps me to pay the bills so I can keep running Imar.Spaanjaars.Com, providing fresh content as often as possible.



Feedback by Other Visitors of Imar.Spaanjaars.Com

On Wednesday, July 28, 2010 4:17:16 PM JEREMY said:
Very nice.  Why not change the cursor to a hand when you hover over the tr

onmouseover="document.getElementById(this.id).style.cursor = 'hand';"
On Wednesday, July 28, 2010 4:24:31 PM JEREMY said:
sorry needs to be 'pointer' to work in Firefox

onmouseover="document.getElementById(this.id).style.cursor = 'pointer';"
On Wednesday, July 28, 2010 4:30:36 PM Imar Spaanjaars said:
Hi JEREMY,

Agreed that a pointer cursor is a good idea. However, using onmouseover="document.getElementById(this.id).style.cursor = 'pointer';" to accomplish that defeats the whole purpose of this article: unobtrusive JavaScript.

Everything to accomplish this is already in place; all you need to do is add cursor: pointer; to the .Highlight class:

.Highlight
{
  background-color: #dcfac9;
  cursor: pointer;
}

I just updated the demo page and will update the article shortly.

Thanks for your suggestion.

Cheers,

Imar
On Thursday, August 19, 2010 5:32:14 PM Johnny said:
There is a glitch.  When you navigate back to the page with the table from yahoo.com the highlighting is reversed.
On Thursday, August 19, 2010 5:41:13 PM Johnny said:
May I suggest removing this:

// Apply a class on mouse over and remove it on mouse out.
      $('#link-table tr').hover(function ()
      {
        $(this).toggleClass('Highlight');
      });

And adding this in the css:

#link-table tr:hover {
    background: #dcfac9;
    cursor: pointer;
}
On Friday, August 20, 2010 6:33:09 AM Imar Spaanjaars said:
Hi Johnny,

Not sure what you mean with "the highlighting is reversed". It probably depends what you hover over (e.g. where your mouse is) when you return as the highlight is applied dynamically.

Good suggestion with the hover class, except that it won't work in IE 6 as it doesn't support the pseudo selector :hover on anything other than the a element.

Cheers,

Imar
On Wednesday, November 03, 2010 12:44:47 AM Chris said:
Can you set the Javascript to ignore table headings (#link-table tr th) as I don't want these to be highlighted or clickable. I know this is probably easy but I have no javascript nouse
On Wednesday, November 03, 2010 7:32:58 AM Imar Spaanjaars said:
Hi Chris,

You can use has(td) to limit the tr's to those containing at least one td, like this:

$('#link-table tr:has(td)').hover(function ()
{
  ...
});

Additionally, you may also need to hide the first th (if you strictly follow my example):

$('#link-table th:first-child').hide();

For more information:

http://stackoverflow.com/questions/530513/jquery-how-to-select-a-tr-that-contains-ths
http://api.jquery.com/has/

Cheers,

Imar
On Wednesday, November 03, 2010 10:57:27 PM Chris said:
Thanks Imar worked a treat and I managed to learn some more jquery/javascript. Great little script

Thanks :-)
On Friday, February 04, 2011 7:42:56 PM Osman said:
Thank you very much for this !!!!!!!!!!!!!!!!!!!!!!!!!!!
On Sunday, November 20, 2011 5:28:10 PM Oldman said:
Nice and helpful post! Thanks Imar!
I've a question about a special usercase:
I have a tr with some td where the last td contains a checkbox. I really would like to have the checkbox checked with the row click - how can that be done? Any idea?
As a sample where such is done is phpMyAdmin's database view - though hard to figure out how they do it ...
On Monday, November 21, 2011 1:45:50 AM Imar Spaanjaars said:
Hi Oldman,

Inside the last block that gets the URL, look for a checkbox instead and then toggle its state using something like this:

var checkbox = $(this).find('td input[type=checkbox]')[0];
checkbox.checked = !checkbox.checked;

You find a demo here:

http://imar.spaanjaars.com/Demos/FAQs/FullRowSelectjQuery/Checkbox.html

Cheers,

Imar
On Wednesday, November 23, 2011 2:23:25 PM Oldman said:
Hi Imar,
thanks very much for xour very fast reply and code sample!
Since my user case is a PHP script where I have already css embeded, I dont want to rely on any external files, thus want to avoid to rely on the external j-query.js ...
After some more struggling I finally found a way to do it directly in the tr tag:
TR ONCLICK=\"document.nameofform.nameofcheckbox.checked=!document.nameofform.nameofcheckbox.checked;\"
this seems to work fine except for one nitpick: the checkbox itself cant be checked any more - now its mandatory to at any place inside the row except the checkbox itself ...
well, I think I can live with that; but if anybody knows how to solve this let me know!
thanks again!
On Wednesday, November 23, 2011 3:09:19 PM Imar Spaanjaars said:
>> Since my user case is a PHP script where I have already css embeded, I dont want to rely on any external files

I am not sure I see the relation between PHP, CSS and external files....

Imar
On Tuesday, November 29, 2011 1:58:49 AM Abimbola said:
Good trick, well appreciated
On Monday, February 10, 2014 7:54:12 PM Mat said:
I am using http://gettopup.com/ to open a popup link.
Works very well on a 'normal' page, but I can't get it to work with the above.

Can you give me a hand?
On Tuesday, February 11, 2014 4:18:16 PM Imar Spaanjaars said:
Hi Mat,

I am not familiar with gettopup.com, so I can't recommend anything.

Cheers,

Imar

Talk Back! Comment on Imar.Spaanjaars.Com

I am interested in what you have to say about this article. Feel free to post any comments, remarks or questions you may have about this article. The Talk Back feature is not meant for technical questions that are not directly related to this article. So, a post like "Hey, can you tell me how I can upload files to a MySQL database in PHP?" is likely to be removed. Also spam and unrealistic job offers will be deleted immediately.

When you post a comment, you have to provide your name and the comment. Your e-mail address is optional and you only need to provide it if you want me to contact you. It will not be displayed along with your comment. I got sick and tired of the comment spam I was receiving, so I have protected this page with a simple calculation exercise. This means that if you want to leave a comment, you'll need to complete the calculation before you hit the Post Comment button.

If you want to object to a comment made by another visitor, be sure to contact me and I'll look into it ASAP. Don't forget to mention the page link, or the QuickDocId of the document.

For more information about the Talk Back feature, check out this news item.