MooTools Zebra Table Plugin

By  on  

I released my first MooTools class over a year ago. It was a really minimalistic approach to zebra tables and a great first class to write. I took some time to update and improve the class.

The XHTML

<table class="list-table" cellpadding="0" cellspacing="0">
	<tr>
		<th><b>Award</b></th>
		<th><b>Actor</b></th>
		<th><b>Film</b></th>
	</tr>
	<tr>
		<td>Actor In A Leading Role</td>
		<td>Daniel Day-Lewis</td>
		<td>There Will Be Blood</td>
	</tr>
	<tr>
		<td>Actress In A Leading Role</td>
		<td>Marion Cotillard</td>
		<td>La Vie en Rose</td>
	</tr>
	<tr>
		<td>Actor In A Supporting Role</td>
		<td>Javier Bardem</td>
		<td>No Country For Old Men</td>
	</tr>
	<tr>
		<td>Actress In A Supporting Role</td>
		<td>Tilda Swinton</td>
		<td>Michael Clayton</td>
	</tr>
	<tr>
		<td>Directing</td>
		<td>Joel Coen and Ethan Coen</td>
		<td>No Country For Old Men</td>
	</tr>
</table>

You may have as many tables as you want.

The CSS

.highlight			{ background:#d5fcdc; }
.even					{ background:#fff; }
.mo					{ background:#e3f1fb; }
.odd					{ background:#eee; }
.list-table th		{ padding:5px; background:#ddd; border-bottom:1px solid #999; text-align:left; font-weight:bold; }
.list-table td		{ padding:5px 20px 5px 5px; border-bottom:1px solid #ddd; }

The above are the classes are configurable using the plugin's options.

The MooTools JavaScript

var ZebraTable = new Class({
	//implements
	Implements: [Options,Events],
	
	//options
	options: {
		elements: 'table.list-table',
		cssEven: 'even',
		cssOdd: 'odd',
		cssHighlight: 'highlight',
		cssMouseEnter: 'mo'
	},
	
	//initialization
	initialize: function(options) {
		//set options
		this.setOptions(options);
		//zebra-ize!
		$$(this.options.elements).each(function(table) {
			this.zebraize(table);
		},this);
	},
	
	//a method that does whatever you want
	zebraize: function(table) {
		//for every row in this table...
		table.getElements('tr').each(function(tr,i) {
			//check to see if the row has th's
			//if so, leave it alone
			//if not, move on
			if(tr.getFirst().get('tag') != 'th') {
				//set the class for this based on odd/even
				var options = this.options, klass = i % 2 ? options.cssEven : options.cssOdd;
				//start the events!
				tr.addClass(klass).addEvents({
					//mouseenter
					mouseenter: function () {
						if(!tr.hasClass(options.cssHighlight)) tr.addClass(options.cssMouseEnter).removeClass(klass);
					},
					//mouseleave
					mouseleave: function () {
						if(!tr.hasClass(options.cssHighlight)) tr.removeClass(options.cssMouseEnter).addClass(klass);
					},
					//click 
					click: function() {
						//if it is currently not highlighted
						if(!tr.hasClass(options.cssHighlight))
							tr.removeClass(options.cssMouseEnter).addClass(options.cssHighlight);
						else
							tr.addClass(options.cssMouseEnter).removeClass(options.cssHighlight);
					}
				});
			}
		},this);
	}
});
	
/* do it! */
window.addEvent('domready', function() { 
var zebraTables = new ZebraTable();
});

The improvements to this class include:

  1. General MooTools style consistency
  2. CSS class flexibility
  3. Checks to make sure the table heading rows (rows with "th") are untouched
  4. You may use the zebraize method after class initialization
  5. Table highlighting has been separated

The class is still very basic. This plugin does not contain sorting functionality nor was it designed to.

Need basic table highlighting? Download it!

Recent Features

  • By
    7 Essential JavaScript Functions

    I remember the early days of JavaScript where you needed a simple function for just about everything because the browser vendors implemented features differently, and not just edge features, basic features, like addEventListener and attachEvent.  Times have changed but there are still a few functions each developer should...

  • By
    Facebook Open Graph META Tags

    It's no secret that Facebook has become a major traffic driver for all types of websites.  Nowadays even large corporations steer consumers toward their Facebook pages instead of the corporate websites directly.  And of course there are Facebook "Like" and "Recommend" widgets on every website.  One...

Incredible Demos

  • By
    CSS Vertical Centering

    Front-end developing is beautiful, and it's getting prettier by the day. Nowadays we got so many concepts, methodologies, good practices and whatnot to make our work stand out from the rest. Javascript (along with its countless third party libraries) and CSS have grown so big, helping...

  • By
    Multiple Backgrounds with CSS

    Anyone that's been in the web development industry for 5+ years knows that there are certain features that we should have had several years ago. One of those features is the HTML5 placeholder; we used JavaScript shims for a decade before placeholder came...

Discussion

  1. Seeing how you can accomplish this with some CSS, PHP + Modulo operator and loop I’m not sure how much sense it makes to rely upon JS to do this task for you.

    Unless you’re not exporting items from a database. But if that’s the case, then your tables will most likely be short anyways making it easy to just add the class names yourself to alternating rows.

    Cool, and works well but I still ask myself if JS is really the tool to rely on for the job…..

    // Tim

  2. Jacob

    click function can be made simpler…

    click: function() {
        tr.toggleClass(options.cssMouseEnter).toggleClass(options.cssHighlight);
    }
    
  3. @Jacob: I believe I had that at first but the cssHighlight was causing issues once the item had been clicked off.

  4. Jacob

    @Tim you can’t do this with CSS if it is to work the same in IE 6 & 7 tho can you?

  5. @Jacob: You couldn’t with the hover — IE6 wouldn’t like that. In my opinion, adding special classes/colors in PHP is really ugly, although a tad safer than JS.

  6. nice tutorial! additional information for me! thanks.

  7. Alexander

    Great plugin!, already implemented it.

    However, i would like to know how do i do if i want the previous selected row to go back with the previous tag once i click or select another row.

    Regards,
    Alex!

  8. Cool, and works well but I still ask myself if JS is really the tool to rely on for the job…..

    I think it’s ok in this case, it’s only for aesthetic, so leaving this job to the client side, even though it’s not a huge task for the server, sounds like a good idea.

  9. Ahmed

    Omg, you have no idea how much pain in the ass this will save me

  10. Nice work! But, I have a question. Is this posible to make something like this for definitions lists?

  11. @Hiway: Yep, you’ll just need to modify the class to look for the proper XHTML tags.

  12. @David Walsh: Thanks, David! That’s OK. But, in your JS code you are working basically only with <tr>-element, and almost the whole formating applying to this element. In that time, when in the list of definitions we don’t have general element for <dt> & <dd> exept <dl>, but one list of definitions can have many <dt> & <dd>, and exactly for these ones we need to apply a “Zebra” formating.

  13. @david: Why aren’t you just using CSS3 nth-child selectors (http://tinyurl.com/czhlp2)? MooTools support CSS3, and zebra striping is quite easy with CSS3-selectors.

    I’ve made a rough example with mootools here: http://ljd.dk/loot/mootables.html. I’ve only tested in FF3, IE8 and IE8 compatability view, but so far it seems to works just like yours with less code.

    Maybe I’m misunderstanding something, but imho it wouldbe easier to use CSS3 selectors. Thanks for a great blog!

  14. This is way easier with jQuery if you want to follow the JavaScript route.

    eg: $("myTable tr:odd).css("background-color", "#000"); would colour the odd rows.

  15. @Phil: Writing that in Moo would be just as short — my class does much more than simple color every odd row differently.

  16. Nice!

    I would use <thead> for the headers and <tbody> for the data rows, and that way save the <th> check.

  17. Matt

    Hmm it would be very cool if the zebratable are dynamically. A function for addRow or something like this :)

    I tried to make but without success :/

  18. I’ve been modifying this plugin somewhat for a project I am working on, and I’ve encountered some problems with it.

    The project I am working on involves hierarchical data in a table, arranged as a series of ‘entry’ rows and ‘folder’ rows. Clicking on a folder row hides or shows the corresponding hierarchy of entries or subfolders. This was easy enough, but I wanted to use this class to recolour the table rows dynamically (as hiding a bunch of rows may throw off the zebra effect).

    Modifying the code so that it checked for tr.style.display != 'none' was trivial, as was adding the extra voodoo to make the zebra effect work independently of row number, but then I found the code did not work reliably after more than one call.

    The problem was actually something I should have noticed from the start: zerbarize() does tr.addClass(klass).addEvents( ... ); *but it doesn’t remove the style classes or events before doing so*, so each call to zebraisze() is just adding classes and event handlers rather than replacing the existing ones!

    In the end, I used the following code:

    var options = this.options, klass = pos % 2 ? options.cssEven : options.cssOdd;
    
    // We might not know which class we have (if any), so check for either
    if(tr.hasClass(options.cssEven)) {
        tr.removeClass(options.cssEven);
    } else if(tr.hasClass(options.cssOdd)) {
        tr.removeClass(options.cssOdd);
    }
    
    // This is rather harsh, but provided the only events get added in zebraize() 
    // it should be safe enough...
    tr.removeEvents();
    
    //start the events!
    tr.addClass(klass).addEvents(..... etc....
    

    I can link you to a pastebin of the complete modified version if you’re interested.

  19. Heikki Naski

    “Seeing how you can accomplish this with some CSS, PHP + Modulo operator and loop I’m not sure how much sense it makes to rely upon JS to do this task for you.”

    Outputting the stripes server-side, you’d need to add that bit of logic to every table you output. It’s not much code, about 5 rows, but it’s duplication nonetheless and requires testing each table separately. Using JS to modify all tables of say, given class or id, you’d have the logic in just one place, with the benefits of centralized control.

    Of course, if you happen to have a method of generating the tables through a single routine in the server-side code, you’d then only have to code the striping once, but a lot of us don’t probably have that luxury always, especially with legacy apps.

    Using PHP would obviously work without JS, so it all depends on can you trust the user to have JS on.

Wrap your code in <pre class="{language}"></pre> tags, link to a GitHub gist, JSFiddle fiddle, or CodePen pen to embed!