« Previous | Main | Next »

Sangeeta asks the CSS Guy how to create a table like Orbitz's airline flights scheduling and pricing matrix

Sangeeta wrote about a matrix she'd like to create that would give an indication of relationships among the information provided. She elaborates:

...For example - clicking on a cell should highlight the associated cell in the top row and left most column.

One good example is orbitz.com.

(You have to actually perform a search to see the actual matrix.) The top row consist of the airline names and the left column is non-stop, 1 stop or 2 stop flight...as you move your cursor, the color of the associated top cell and left most cell changes to yellow...

Nice idea. I'll cover one way to create the effect using JavaScript and CSS. (For those who have been here before, I realize there is lots of repeated material here from my previous post, but that's the good thing about reusable JavaScript... it's reusable in different situations!)

Orbitz's Flight Stops and Price Table

For those who like to skip ahead: view the final example

Getting Started

A table of this type has headings across the top as well as down the left side. I'll use a thead with th's across the top, line the left column of the tbody with th's, too. like so:

A basic table with a thead and tbody, with some table heading cells being the first cell of each table row in the tbody

View example 1, the bare table.

Who are we kidding? View example 2, a styled table.

Next Step: Add class

To help establish the relationship between cells, add classes. (This will be used by the JavaScript to know which cells to highlight.

<table>
  <thead>
    <tr>
      <th class="null">
      <th class="stones">
      <th class="u2">
      <th class="crue">
    <tr>
  </thead>
  <tbody>
    <tr>
      <th>
      <td class="stones">
      <td class="u2">
      <td class="crue">
    </tr>
    ...
  </tbody>
</table>

View example 3, classes added. (Or don't, since there is not much visually different yet).

Next Step: Establish what an selected state looks like

I'm going to use class="on" again to add the highlight to the appropriate cells.

<table>
  <thead>
    <tr>
      ...
      <th class="u2 on>
      ...
    </tr>
  </thead>
  <tbody>
  ...
    <tr>
      <th class="on">
      <td class="stones">
      <td class="u2 on">
      <td class="crue">
    </tr>
   ...
  </tbody>
</table>

and the CSS...

tbody td.on {background:#f3f0e4;}
thead th.on {background:#ffe068;}
tbody th.on {background:#ffe068;}

View example 4, the selected state.

Next Step: Using JavaScript

We can't really use :hover to make this stuff work. Instead, we're going to highlight the appropriate cells using onmouseover and onmouseout events.

In English, here's what we want to happen:

  1. When someone hovers over the Nikki Sixx table cell
  2. add class="on" to the Nikki Sixx cell
  3. as well as adding class="on" to the "Mötley Crüe" and "Bass Guitar" cells.
  4. When someone moves their mouse away from that cell, remove class="on" from all of those cells we just added to previously.

Here are the tools needed to do that:

  • A javascript function called getElementsByClassName, which allows us to target elements based on their class value. (via Robert Nyman)
  • A javascript function called addClassName (via Robert Nyman). This function will be used to add "on" as a class name to our desired cells.
  • A javascript function called removeClassName, (via Robert Nyman). This is used to unselect cells by removing the "on" value from their class attributes
  • A custom javascript function to tie the behavior together.
  • A javascript function called addLoadEvent (via Simon Willison), which is just a way of attaching these behaviors when the page loads instead of putting onmouseover and onmouseout event attributes to every cell by hand.

And here's the end result - view example 5, the final product. Just view source to copy it and take it with you.

See also

I could see how someone could want to apply highlights to entire rows and entire columns (as opposed to just the header cell of that row or column)... it wouldn't be a long stretch from this (corresponding how-to post found here).

Also, here's a way to indicate relationships similarly to what is described above, but without JavaScript.

Comments (11)

Fabrice said:

Great post, clean code. I would use event delegation for the highlighting though, as this would be faster on big tables.

Liz said:

This is awesome! The only problem is that Ron Wood is not the bass player for the Rolling Stones. ;)

hafefe said:

This is awesome! I really like it! Sorry for the stupid question, but what sould i do if i have more than one table in one page? How could the JavaScript handle them?
Thanks again!

CSS Guy said:

The easiest way to go from my example to multiple tables is to have a unique id for each table, and just add an extra addLoadEvent line that calls those ids.

For example, right now I'm declaring the id of the table I want to use inside the javascript function, like so:

var table = document.getElementById('rockartists');

which doesn't let me reuse that same function for other tables. But, if I changed the function to take an argument:

function makeTheTableHeadsHighlight(tableId) {}

then change the var table line to read like this:
var table = document.getElementById(tableId);

then call it with these addLoadEvent lines:

addLoadEvent(function() {
makeTheTableHeadsHighlight('myspecialtable');
makeTheTableHeadsHighlight('mylessspecialtable');
});

hope that helps!

hafefe said:

Thank You for the help, I'll try it! Really-really big thanks, and happy new year :)

This is awesome! I really like it! Sorry for the stupid question, but what sould i do if i have more than one table in one page? How could the JavaScript handle them?

dan said:

what about if I only wanted the whole row to highlight upon mouseover?

Dan said:

nice, what would you add if you wanted the whole row to highlight on mouseover?

Jeff said:

I find this rather ironic. I was searching the Internet for a CSS solution to creating a table of information. (Personally, I see all web pages as a bunch of tables within tables, but I digress.) I wanted to see what a current CSS guy has to say about the latest CSS attempt at getting rid of tables. (I love Zen Garden by the way, but I digress.)

And, what I discovered was a "CSS Guy" as one of the top ranked answers in Google and the CSS Guy tells me to use HTML tables!

I just find that ironic.

I've used CSS since the first browser supported it. However, I've always used tables for layout as well. I think I am going to turn my hearing-aid off when they berate the world for using HTML tables. (Oh, and I think I'll continue to close my table cells as well - just like you closed the table rows and the tables themselves.)

Also, if you've looked at the newer table specs in CSS, you should already know that it makes little sense to use them. They abstract the table concept to such a degree that they are almost a direct replacement for HTML tables. Hence, they simply make development more difficult.

I think HTML tables will rule for quite some time.

CSS Guy said:

@Jeff:

Tables aren't 'bad', just wrong for layout. Tags should be used for their intended use.

simon Cooper said:

I am looking to create a table with 8 boxes cross and about 10 to 15 boxes deep. Each box will be 40 x 40 pixels with a gap of 10 pixels between each box and within each box there will be an image and it links to other pages. I did one at the start of my home page but it took a while to do it. I am wondering if there is a better way?

Post a comment

If you want to show tags, use &lt; and &gt; for < and >, respectively.

Ask the CSS Guy

About this site.

Send questions, including links or code, to askthecssguy@gmail.com.

Subscribe to this blog's feed.

About

This page contains a single entry from the blog posted on September 23, 2007 12:05 AM.

The previous post in this blog was Creating a table with dynamically highlighted columns like Crazy Egg's pricing table.

The next post in this blog is Job Opportunity in Memphis, Tennessee.

Many more can be found on the main index page or by looking through the archives.