The Lowdown
I searched the depths of google in an attempt to find a similar script (not tied to a JavaScript framework) that properly dealt with both rowspan & colspan use within the table but to no avail – which, of course, meant that I had to attempt to write my own.
At a glance…
- Unobtrusive and nameSpace friendly
- Can Zebra stripe the table
- Supports row hover, column hover and cell hover effects
- It can intelligently deal with rowSpans and ColSpans
- Table rows can be selected “onclick” and a callback function (or Object method) can be defined to programmatically deal with the user’s selection.
- It’s fast compared to similar scripts, even in Internet Explorer
Zebra striping the table
To zebra stripe every alternate table row, just give the table a className of the form rowstylealt-XXX where XXX represents the className to give each alternate row, for example; giving the table a className of rowstylealt-alt will give each alternate row the class alt.
Row & Column highlighting
Row highlighting
To highlight the current row i.e. the row the mouse is currently hovering over; just give the table a className of the format rowstylehover-XXX, where XXX represents the class that will be given to the current cell’s parent TR node.
Column highlighting
To highlight the current column, just give the table the className colstylehover-XXX, where XXX represents the class that will be given to each node within the current column scope.
Highlighting the “current” cell
To highlight the current cell, just give the table a className of the format cellhover-XXX, where XXX represents the className that will be given to the current cell.
Internet Explorer info
Both the rowstylehover and cellhover classNames will be used only if using Internet Explorer as all other A-grade browsers understand the :hover pseudo class.
Internet Explorer 7, when in “standards mode”, understands the :hover pseudo class and so the script will only use the aforementioned classNames should the user be using any version of Internet Explorer smaller than 7 or if using Internet Explorer 7 and the page is rendered in “quirksmode”.
Row selection
To enable users to click on a row in order to “select” it, just give the table a className of the format rowselect-XXX, where XXX represents the class to give the current cell’s parent TR node after the click event has fired.
Single row selection only
Should you wish that only one table row can be selected at a time, give the table the class rowselectsingle.
The callback function
Enabling users to select table rows is rather dull if nothing can be done with the user’s selection. To this end, the script enables you to define a reference to a JavaScript callback function (or Object method) that is itself passed an Object detailing the table, the cell clicked, the row clicked, the action to be taken (i.e. add/remove) and the list of currently selected table rows i.e:
{
"table": /* The table */,
"cell": /* The cell that was clicked */,
"row": /* The row to be added or removed */
"remove": /* Are we attempting to remove the row (T/F) */
"rows": /* An array of currently selected TR nodes */
}
The callback function should always return a Boolean value that indicates to the script if it should continue with the add or remove action. This enables you to filter out rows from the selection using bespoke criteria.
Using a bespoke callback function
Should you wish to define a specific callback function for the table, just give the table a className of the format rowselectcallback-XXX, where XXX represents the name of the JavaScript function to call after a row has been selected or deselected by the user.
Using an Object.method as a callback function
Should you wish to define an Object method as a callback function, just give the table a className of the format rowselectcallback-XXX, where XXX represents the name of the JavaScript Object method to call after a row has been selected or deselected by the user.
In order to enable the parsing of the “.” (dot) Object notation, the XXX className has all “-” characters replaced by the “.” character, for example; giving the table the className rowselectcallback-anObject-aMethod will mean that the script will attempt to use anObject.aMethod() as the callback function.
An example of defining an Object method in this way can be viewed within the table actions demo.
The default callback function
If no className of the format rowselectcallback-XXX exists, the script will attempt to call a function called “rowSelectCallback”.
Programmatically clearing the user selection
Should you wish to programmatically remove the users selection, just call the method fdTableActions.deselectAllRows, passing in the ID of the table as an argument, for example; calling fdTableActions.deselectAllRows(‘testTable’); will remove the user selection for the table with an ID of “testTable”.
On the shoulders of giants
This work is based on a script originally developed by the veritable Richard Cornford – a man that can write rather stunning JavaScript code and who has already forgotten more about closures than I will ever know.
The License
The script is released under a creative commons Attribution-ShareAlike 2.5 license. Should you use the script within a commercial context please think about clicking the payPal donate button – it’s certainly not an obligation but it would most certainly put a smile on my face.
Demo, downloads and updates
Tested in Internet Explorer 6, Opera 9.01, Safari 3.0.3 (Windows) and Firefox 2.
View the table actions demo or download the 23k uncompressed JavaScript source code (you can compress the script down to 6k by using Dean Edwards Packer if the size is an issue).
15/04/2008 (v0.8):
- Internet Explorer specific bug fix dealing with the mouseout event
10/04/2008 (v0.7):
- Small bug fix for the row selection code
15/01/2008 (v0.6):
- Small bug fix and demo code update
22/11/2007 (v0.5):
- Removed an Internet Explorer memory leak
19/11/2007 (v0.4):
- Reduced the processing overhead required to calculate each column’s nodelist even further
- Added code that requires callback functions to return a Boolean value
- Added more information to the Object passed to the callback function (“remove” and “row”)
- Added the “rowselectsingle” functionality
18/11/2007 (v0.3):
- Reduced the processing overhead required to calculate each column’s nodelist
- Added the callback function “Object as argument”
16/11/2007 (v0.2):
- Rewrote the script to be kind to Opera
- Added the “colstylehover” className
15/11/2007 (v0.1):
- Creation

Previous Comments ~
This is a fabulous widget and follows your tradition of simple, unobtrusive and visually stunning widget creation to the letter. Great work.
@ Don: Hi Don, not so fast… I’ve found that it slows down completely in Opera (which is suprising as Opera is usually the fastest of the lot)... I’ll look into it at the weekend and hopefully report back some good news Monday… thanks for comment!
Just as an aside, also.
Your ‘testing’ list has Safari 3.0.3 for Windows. The 3.0.4 beta is out now which fixes a lot of known issues. It’s probably worth upgrading.
This is awesome…
I’d like to use this on a webform I’m creating — how hard would it be to convert this so that the highlighting happens when a form field within a row is clicked instead? I don’t have a huge amount of programming background, so if you have an example, it would be greatly appreciated!
Many thanks,
Josh
@ Kit: Hi Kit, I only upgrade when the browser’s out of beta (yep, I’m old-skool like that).
@ Josh: Hi Josh, it would be pretty easy in fact. You would have to remove the mouseover/mouseout event from the table (as it’s no longer needed) and change the click event to check for form elements. If the source of the event came from a form element, then find the parent table row and do the highlighting…
Regards,
Brian
On line 64 of the script:
// Do we even need to continue?
if(!(rowAlt && rowHover && colHover && rowSelect && cellHover)) continue;
This seems to skip over any table which does not have ALL the possible actions defined. I assume that this is not the desired effect, and what is actually desired is skipping tables that do not have ANY of the possible actions defined. The line should read:
if(!(rowAlt || rowHover || colHover || rowSelect || cellHover)) continue;
I only needed row hover highlights and select highlights, so colHover and cellHover were not defined for my table. Only after changing this line would rowHover and rowSelect function.
@ Matthew: Hi Matthew, well spotted sir. I’ll update the code today.
First of all ….excellent piece of work, and if ‘imitation is the sincerest form of flattery’...you are well flattered matey !
Just one question tho’. I have created a table and can sort on each column of data. I have also added an onmouseover event which highlights the row
and does a call back to a database to show further details for that row and which are displayed in another table. All excellent stuff.
Here it comes…..when I sort on the first column I cannot get the details from the onmouseover event. The rows still highlight as the mouse passes over them.
Not being a javascript guru, I added the onmouseOver event in the php serverside…I hear you cringing from here…How SHOULD I add the onmouseover event.
Hi John, here’s how to add the events (I’m assuming that your using the Table Actions script and using it’s addEvent method…):
Hope this helps,
Brian
P.S. Glad you like the script!
Once again thanks, I have cobbled together my code with yours for adding events and it all works fine…..I found your method for identifying browsers a real boon as well. As you say short but really sweet !
Anudder thought about the script..I want to be able to use my own call back method a la rowselectcallback-myobject-showdetails and I have implemented this as above. I would like to be able to select the row and highlight it as selected, as I want to be able to amend the details shown in a side table for that row. How can I do this ? If I use my own callback it prevents me from selecting the row ! Any suggestions would be appreciated ….
ps my table is declared as: id=“myTable” cellpadding=“0” cellspacing=“0” class=” rowstylehover-rowHover rowselect-rowSelect rowselectcallback-myobject-showdetails sortable-onload-1 no-arrow rowstyle-alt colstyle-alt paginate-10 max-pages-7
Kind Regs.
John
sorry for the dumb question….just needed to RTM I quote “The callback function should always return a Boolean value”.
some people never learn !
John
Is it possible to create such a table dynamically ? I have created a table as per your script and it works perfectly. I was considering using it in a Master/Detail scenario. The user places the mouse over the row in the master table and on mouseenter a callback is made to the db to get the details for this row. I wanted to then create a small table in a div which is sortable and paginated. A penny for your thoughts…
@ John: hi John, it is indeed possible. Just remember to call the .init methods of both the pagination & tablesort scripts, passing in the ID of the dynamically created table.
As an aside, I would hold back on initiating the Ajax request until the cursor has hovered over the line for at least than 1 second (i.e. use a setTimeout to call the actual Ajax request and clear this timeOut each time you mouseover a TR/TD).
Regards,
Brian
Brian, I had actually thought that thats all I needed but hadn’t tried it. There are in fact 2 callbacks at present to the db and 2 tables are filled with relevant data as a result. There is a performance hit and I will combine the 2 calls into one in the near future. Thanks for your help and to all you ‘cut an’ paste coders’ out there…pay the man….
This is truly excellent.
I’ve been experimenting with both this action table and the equally excellent sortable version and was hoping that I’d be able to combine the two areas of functionality into a single table control. Basically I’d like to have the ability to sort columns as well as select multiple items in the table. Unfortunately my JavaScript capabilities are somewhat limited and I couldn’t work out how to achieve this. Do you have any examples of tables that behave in this way?
Many thanks for any help.
Jan
@ Jan Maes: Hi Jan, the two scripts work together. Just download them both and add the required classNames to the table and th tags.
Hi, Thanks for the quick response. I had actually tried that and it wasn’t working. I assumed that it was going to be a more complex process to get it going. I’ve just reloaded my project and realised that one of the references to the JavaScript files was pointing to the wrong folder (foolish error). I corrected it and it worked first time. Apologies for wasting your time, I really should have been more careful.
Thanks again for your help. I’m hugely impressed with these tables. Brilliant!
When placing a table within a scrollable DIV the header disappears when scrolling and then clicking on the table. Do you notice the same issue? Can this be fixed?
@ Jan Maes: Hi Jan, glad to hear you got it working.
@ Josie: Hi Josie, as stated just above the comment box, the browser and O/S info would be nice to have as without it I can’t test the problem. F.Y.I: I can’t reproduce the problem in IE6 or FF.
@ Jan Maes: Hi Jan, glad to hear you got it working.
@ Josie: Hi Josie, as stated just above the comment box, the browser and O/S info would be nice to have as without it I can’t test the problem. F.Y.I: I can’t reproduce the problem in IE6 or FF.
This is a great script! I have one question, if I would like to populate my tables with data from a mysql database, what would be the best way to do it? at the moment i can get it populated, but the sorting doesn’t work then. (seems like its only trying to sort my first row). Any pointers & suggestions would be great! Sorry if this sounds a stupid, bit of a n00b when it comes to Java/AJAX.
@ Darrell: Hi Darrell, have you remembered to call the tableSort.init method after redrawing the new table data?
If so – and if you redraw the entire table, have you remembered to add the required classNames to the TH tags?
Regards,
Brian.
Brian,
I haven’t done that, not to sure where i should call it. The few examples i studied doesn’t use “tableSort.init”. Can i email you my code? (If you don’t mind.) or must i post it here?
—
Darrell
@ Darrell: Hi Darrell, check the source code to the dynamic table demo which calls the init method after redrawing the table in order to reinitialise the sort script.
Fantastic work! I’ve been looking at the various datagrid / table tools out there, and have decided on yours, so pleased when I stumbled on it.
However I was just wondering if anyone has added to the script to allow for fixed headers, or is it something you are thinking of adding?
Regards,
Toby
What I am looking for is a script that has sorting, pagination and row highlighting (which link to a new page).
Since you have all three in separate scripts, how do I combine them? Do I just put them all in the same file and call it? Or is there a ‘trick’ to using all three? I haven’t seen any comments or hints in regards to this.
Thank you for making them available.
@ Toby: Hi Toby, double post? I answered your question in the coments to the tablesort script.
@ Rob: Hi Rob, theres no trick, just link them in the head of your page as normal and add each script’s required set of classNames.
I really like this script, but I am making a stupid mistake I am sure…I am confused about how I declare the different classes for my rows. I am assuming these are like css classes. I want to simply alternate the colors of my rows, so I tried to put:
.row0 { background-color: #ffffff;
}
.row1 { background-color: #f0f0f0;
}
and then table class=“rowstylehover-row0”
but that didn’t work.
Any help would be great. I love your script!
@ Jared: Hi Jared, try this in your stylesheet instead:
tr td { background:#fff; }
tr.row0 td { background:#f0f0f0; }
…and don’t forget, it’s “rowstyle-row0”, not “rowstylehover-row0”. Read the section “Zebra striping the table” within the article for further info.
Regards,
Brian
Hey thanks, that made it work for the alternate colors. However, now I’m trying to use tableActions.js to use the commands such as hover over the current row.
So, I add the class rowstylehover-hov on my table. And in my styles thing I add:
tr.hov td{ background:yellow; }
But that doesn’t work. I’ve tried changing tr.hov td{ background:yellow; } to like hov td{...} or td.hov tr{ } because I am guessing thats the problem, but nothing works.
Thanks
I figured it out… it works in IE, just not my firefox. Thats weird
Actually, I looked at your demo and saw that yours works in my browser. I have no idea what I’m doing wrong.
In my php file I have the style
tr.rowHover td{ background-color:#F0F0F0; }
My table is:
a b c 1 3 5The hover works in ie, but not firefox. How does the demo allow it to work in firefox?
Thanks for your help
Nevermind, I got it to work. Thanks for your time!
Hi, that’s a great script, very useful and you same me a lot of time. I use it in some of my project, but now, I have to set up an hover class, everything work, but if I quit the table (only by the right, bottom or left) the row keep the hover class until I pass my mouse on another row in the table. This didn’t happen when I’m quitting the table by the top, where table headers are present.
I use those parameters in the table’s class: sortable-onload-1f no-arrow rowstylehover-rowHover rowstylealt-rowAlt paginate-25 max-pages-7
Oh, and I use the pagination script and if I remove the pagination’s parameters, same thing happen.
I use IE 6 on Windows XP SP2.
Any idea ?
Thanks !
@ jared: Hi jared, it’s the specificity of your CSS thats the problem!
@ Olivier: Hi Olivier, you most probably need to make the BODY have width and height 100% for the mouseout to work.
Hi, I’ve tried your solution but without success. The problem persist.
This is my table:
Col 1 Col 2 Col 3[code]
<table width=“100%” border=“1” id=“tblParticipants” class=“tableau-participants sortable-onload-1f no-arrow rowstylehover-rowHover paginate-25 max-pages-7”> <thead> <tr> <th width=“40%” class=“sortable-text”>Col 1</th> <th width=“30%” class=“sortable-text”>Col 2</th> <th width=“30%” class=“sortable-text”>Col 3</th> </tr> </thead> <tbody>
<% function fetch users from DB %> </tbody>
</table>
[/code]
the function create a row for each user.
the CSS:
table tr.rowHover td, /* Internet Explorer < 7 (and 7 in quirks mode) requires a specific class */
tr:hover td /* All others can use the :hover pseudo */
{ background-color:#ffffff;
}
Thanks for your help !
(In IE7, Win Xp Professional)
If you click down on a row, then drag the mouse to another row before letting up, an error occurs. (I tried this in Firefox and no error occured.)
@ Olivier: Hi Olivier, even with the code provided I couldn’t reproduce the problem. Have you a URL I can look at?
@ Jeremy Downs: Hi Jeremy, I updated the code with a fix. Thanks for the bug report.
Hi,
Sorry, I can’t give you an URI because the site is on the intranet. I’ve desactived the action function and add an mouse over and mouse out event on each generated row because I haven’t time to test it anymore. Time is money… I’ll check this personnally and I’ll continue to inform you.
Thanks
First of all Brian, these scripts are excellent and have enabled us to add a ton of functionality to our pages without much change.
@ Olivier, are you using multiple tables on the same page? It may be related to a problem we’re encountering.
(Shameless segue into my own problem)
The problem I’m seeing is that with multiple tables, when moving the mouse from one table to the next, a row in the target table becomes sticky-highlighted until a mouseover is done on the source table. It took a bit of time but I tracked down the reason.
Here’s a simple example. From my understanding, when you move the mouse from table A to table B, you should encounter two events in the fdTableActions.tableEvent method:
1) event type = “mouseout”, fromElement = “TABLE” (id=“A”), toElement = “TABLE” (id=“B”), this.id=“A”
2) event type = “mouseover”, fromElement = “TABLE” (id=“A”), toElement = “TABLE” (id=“B”), this.id=“B”
When I move my mouse quickly, sometimes there are no events going to the table element for B, but events actually show up going straight to the TD within table B. These are the events I see:
1) event type = “mouseout”, fromElement = “TABLE” (id=“A”), toElement = “TD”, this.id=“A”
2) event type = “mouseover”, fromElement = “TABLE” (id=“A”), toElement = “TD”, this.id=“B”
When event 1 is handled, the newly-selected row in table B is highlighted with the highlightStyle, but it gets registered as the lastRow in the tableCache for table A. When event 2 is handled, the same row in B gets another highlightStyle added to it (class=“highlightStyle highlightStyle”). This isn’t cleared until you mouseover something in table A, “clearing” the pointer that erroneously points to a lastRow in table B. If you’re already aware of this issue and there’s a “best practice” to avoiding it, please let me know.
I haven’t tried playing around with table/cell borders but I’ll see if that fixes or alleviates the problem. I’ll also try to construct a minimal test case to replicate this. I’ve confirmed the problem in Eclipse’s HTML Editor’s preview, as well as IE6. If you need further clarification on the problem, I’ll check here occasionally or you can e-mail me.
Again, great work on the scripts (we’re already using tablesort and considering paginate). They have been immensely useful!
@ Olivier & Dion: Hi guys, I’ve fixed the Internet Explorer bug (by using the propritary mouseleave event and not the mouseout event). Thanks for the bug reports – Dion, you get a gold star for the quality of the explanation, well done.
Regards,
Brian
Brian, the bugfix worked for us. Thanks again for your hard work!
I love this script. Just wanted to mention a typo in the section on zebrastriping, you have rowstyle-alt for the class, but it should be rowstylealt-XXX. It confused me for the longest time why it wasn’t setting the classes until I look at the demo page’s code.
@ Dion: Hi Dion, glad to be of help.
@ Daniel: Hi Daniel, I’ve corrected the appropriate section of the article. Thanks for the warning!
VERY nice scripts!
Is there a way I am not aware of, to allow a link in a table cell to be set to NOT trigger the row selection – I tried in vain to use stopPropagation and cancelBubble to allow a link to work without selecting the row, but allow a click outside the link in the same cell to trigger the selection
@ Michael: Hi Michael, it’s probably just a matter of putting:
if(tr.tagName.search(/select|input|a|button/i) != -1) { return true; }
as the 5th line within the “clickEvent” method.
When you refer to Richard Cornford as ‘veritable’, did you mean ‘venerable’? :-)
@ JohnnyPanic: Hi JohnnyPanic, you may just be right! I should really proof-read things before pressing the save button…
I might just be doing something wrong, but when I use the YUI compressor to minify the table actions script, IE throws an error when trying to load it: “Object doesn’t support this property or method.”
@ Heliologue: Hi Heliologue , and once again, sorry for the late reply… it’s most probably a missing semi-colon or an Internet Explorer conditional compilation statement thats throwing the compressor. I’ll have a check for missing semi-colons my end but can’t do much for the conditional comment support in the YUI compressor.