Table Row and Column Highlighting

Published by Chris Coyier

In mid-2009 I did a screencast about tables which featured how to do row and column highlighting with jQuery. The method in the video isn't nearly as efficient as it could be, so this is an update to that. Shout out to Bronislav Klucka who contacted me about the idea.

Attaching events to table cells is the quintessential example, and also read like a history for event handling in jQuery.

  • Original demo (version < jQuery 1.3 ) - Using .hover() on every single <td>
  • Live demo ( jQuery 1.3 <= version < jQuery 1.4.2 ) - Using .live() on <td>'s
  • Delegate demo ( jQuery 1.4.2 <= version ) - Using .delegate() on <table>

HTML of typical table

Let's assume this markup. There are five columns, and so there are five <colgroup>s. Colgroups allow us to style an entire column without needing to manipulate individual table cells (as table cells in a particular column share no common unique parent).

<table>
    <colgroup></colgroup>
    <colgroup></colgroup>
    <colgroup></colgroup>
    <colgroup></colgroup>
    <colgroup></colgroup>
	<thead>
	    <tr>
	        <th></th>
	        <th></th>
	        <th></th>
	        <th></th>
	        <th></th>
	    </tr>
	</thead>
	<tbody>
    		<tr>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    		</tr>
    		<tr>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    		</tr>
    		<tr>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    			<td></td>
    		</tr>
    	</tbody>
</table>

CSS

Nothing much to see here, just that we will have a class name ready to handle the actual styling of "current" rows and columns.

.hover { background-color: #eee; }

It's best to handle the actual styling information through CSS rather than directly in the JavaScript.

You gotta keep 'em separated

- Offspring

Best Method: Delegate

For jQuery 1.4.2+, the best bet is going to be delegate. Here is the two second overview. You attach a single event listener (efficient!) to the table itself specifying which elements qualify. If anywhere inside the table is clicked, it checks if that click was inside one of the specified elements. If there is a match, it fires the function.

$("table").delegate('td','mouseover mouseout', function(e) {
   // do stuff
});

Our "do stuff" is applying a class name to the row and colgroup, when they are "hovered" over only. "hover" isn't a real event though, the real events are mouseover and mouseleave. Delegate will take a space-separated list of events. Within the function we can test which type of even was fired and act accordingly.

$("table").delegate('td','mouseover mouseleave', function(e) {
    if (e.type == 'mouseover') {
      $(this).parent().addClass("hover");
      $("colgroup").eq($(this).index()).addClass("hover");
    }
    else {
      $(this).parent().removeClass("hover");
      $("colgroup").eq($(this).index()).removeClass("hover");
    }
});

Since delegate is watching the entire table, if new table rows/cells are added dynamically later, they will still behave with this code.

Still good method: Live

Post jQuery 1.3, but pre jQuery 1.4.2, the best method for event handling in a situation like this was .live(). Remember how with delegate we watched the table itself for the specified events? With live, we watch the entire <body> for those events. This has the distinct benefit of allowing new rows/cells to be added dynamically without the need to re-attach events, but with less efficiency than delegate.

However it should be noted that should entire new table be added to the page dynamically, live would continue to work while delegate would not, as the new table would not have delegate attached to it.

$('td').live('mouseover', function(){
    var i = $(this).prevAll('td').length;
    $(this).parent().addClass('hover')
    $($cols[i]).addClass('hover');

}).live('mouseout', function(){
    var i = $(this).prevAll('td').length;
    $(this).parent().removeClass('hover');
    $($cols[i]).removeClass('hover');
});

The old and kinda bad method

Before we had access to live or delegate, or only method was to bind the events directly every single table cell. jQuery still had a helper function for it, but it still meant adding an event listener for every single solitary cell (inefficient!, e.g. lots of browser memory usage). Not to mention that if new table rows or cells were added dynamically, they wouldn't have any of the events attached them that their brethren do.

$("td").hover(function() {
   // do stuff
}, function() {
   // do stuff
});

If you'd like to see all the old nastiness, it's here.

Demo and Download

  • Original demo (version < jQuery 1.3 ) - Using .hover() on every single <td>
  • Live demo ( jQuery 1.3 <= version < jQuery 1.4.2 ) - Using .live() on <td>'s
  • Delegate demo ( jQuery 1.4.2 <= version ) - Using .delegate() on <table>

Download Files

Have a more complex table?

With colspans and rowspans and whatnot? Gajus Kuizinas's Wholly project might be able to help you with highlighting in those cases.