XHTML tables provide several elements to group and structure data, including row groups (
tfoot). Styling row groups with CSS can make data relationships visually obvious. One familiar way to group data visually is with Explorer-style folder icons.
The basic idea is to use
tbody as many times as needed to group each set of rows together. The image above shows a single
tbody element. I think using multiple
tbody elements may not occur to developers because it sounds like there ought to be only one — but that’s not true. Tables can have as many
tbody elements as you want. You can optionally have one (and only one)
tfoot too. Read the Tables in HTML documents part of the HTML spec for more, if you want (there’s no need to for this article).
The next thing to do is add some CSS. The image will go at the far left of the leftmost (first)
td as a background image, and I’ll add some left-padding to keep the text from overlapping the image. I identify the leftmost column with the
Next, the first and last rows in the group need special treatment. The middle rows get a little dotted “tree-view” extender line, but the first row needs a folder icon and the last needs the extender line not to continue downward (because there’s nothing below it to connect to). To accomplish this, the first row in the group gets the
first-child class, and the last gets
class="last-child". Now I can use these to set different background images for the first and last rows in the group.
If I knew that my browser was a Good Browser such as Opera, Firefox or Konqueror, I could use the CSS selector
:first-child instead of adding classes, but since IE is still popular, I’m adding the classes to the HTML instead.
This part is optional, but I like to do it because it keeps the number of images down: use exactly the same image for every row (first, middle and last), and set the
background-position property so a different part of the image will show up (top, middle, and bottom of the image).
That’s it! Here’s a demo.
Another option is to re-code the first row of each group with
th elements instead of
scope attribute can then be set to
rowgroup, which conveys additional semantic meaning about the row and eliminates the need to add the
first-child class to the
tr. Whether I do that depends on the data. I don’t think it makes sense for my demo, but I can imagine data applications where it does. I can also imagine making the leftmost column
th instead of
td in my sample data; that strikes me as appropriate. Regardless of how I do it, if I mark the data up semantically, I can use CSS to reflect that meaning visually.