First, how not to use the table element: as a layout tool. Repeat after me: “Tables are for tabular data. Tables are for tabular data. I will not use tables for laying out a Web page. Tables are for tabular data.” So, now that we’ve gotten that bit out the way, let’s talk about what comprises a semantic, valid table. This is basic table creation 101. Next week, we’ll talk about advanced table features.
Forget the old paradigm
Remember back in the day when this was a complete table? Perhaps one you used as a layout tool? Or one you’ve seen recently in live code and then cried a little inside?
<table>
<tr>
<td>
Hi! I’m some table content. In poorly-developed sites, this might actually be where all of the site content is!
</td>
</tr>
</table>
Great. Enough nostalgia. That is not an OK table for 2010.
The new paradigm: semantic, accessible, complete
What was that mantra? “Tables are for tabular data.” When presenting tabular data, we need some more information about that data. Modern HTML tags help us out there. First, let’s talk about what information we need for a good data table.
Distinction between headings (<th>
) and data (<td>
)
When you’re looking at a table, some cells are heading information. They don’t describe actual data, they describe what the data is. Those cells are t
able h
eadings (th
).
Of course, the bulk of the table cells are t
able d
ata (td
).
You should use the correct cell element for the right type of information.
A title (<caption>
)
Your users need to be able to look at the table and know what it’s about. A descriptive, succinct title helps with that.
Important notes:
<caption>
must be the first child element of the table.- There can only be one
<caption>
element inside of a table.
<table>
<caption>Elements To Use in Proper Tables</caption>
...
Headings (<thead>
)
We talked about using <th>
element above, now let’s talk about where to use them. Short answer: mostly in the <thead>
element.
The <thead>
element is one of three rowgroup elements (the others are <tfoot>
and <tbody>
—more on them later). It gives semantic meaning to a grouping of rows, saying “these rows are the heading of the table.” Combining it with <th>
elements allows you to create a semantic section to describe columns.
Important notes:
- The
<thead>
element isn’t required, however any data that deserves to be in a table deserves to have headings, right? So semantically, you should use it. And again, don’t forget about its use in selectors for progressive enhancement and CSS. - An empty
<thead>
is invalid. It must contain a<tr>
and the same number of header or data cells as the body of the table. - You can use
<td>
elements in it, but again, remember the distinction between those and<th>
. Chances are, you’re definining a heading in the<thead>
.
<table>
<caption>Elements To Use in Proper Tables</caption>
<thead>
<tr>
<th>Tag </th> <th>Attributes</th> <th>Description</th>
</tr>
</thead>
...
Table Footer (<tfoot>
)
The second of three rowgroup elements, the <tfoot>
element designates a group of table row elements as the footer. I can’t harp on about how you should use the <tfoot>
element in every. Single. Table. Because, I admit, you don’t always need a footer for data. Semantically, it can have a few different uses. I use it for things like a total line, footnotes for data, etc. Like <thead>
, it’s not a required child element.
Important notes:
- An empty
<tfoot>
is invalid. It must contain a<tr>
and the same number of header or data cells as the body of the table. - It must come before the
<tbody>
element(s). Straight from the W3C:
<tfoot>
must appear before<tbody>
within a<table>
definition so that user agents can render the foot before receiving all of the (potentially numerous) rows of data.In other words, if you have a lot of data, the
<tfoot>
should be rendered before all of the data. - The
<tfoot>
should be displayed after all<tbody>
elements, despite the fact that it appears before them in the code. However, this is sadly untrue for some older user agents and most HTML as PDF rendering vehicles. It sucks, but those older clients’ use is decreasing, at least.
<table>
<caption>Elements To Use in Proper Tables</caption>
<thead>
<tr>
<th>Tag </th> <th>Attributes</th> <th>Description</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">* denotes optional child elements</td>
</tr>
</tfoot>
...
Table Body (<tbody>
)
The final rowgroup element, <tbody>
defines the body of your table—the section that contains all of your data. There can be multiple <tbody>
elements in the table, if such a grouping makes sense for your data.
Important notes:
- In any table that uses
<thead>
and<tfoot>
elements,<tbody>
is required. Otherwise, it is implicit. You should include it anyway. - For the most part,
<tbody>
will contain a bunch of<td>
elements nested inside of<tr>
elements.<th>
elements are also appropriate if you want to add a heading for that row. - Using multiple
<tbody>
elements is not appropriate for zebra-striping. That should be a progressive enhancement with Javascript.
So, to wrap it up, code for a complete simple, semantic table will look something like this:
<table id="elements-for-tables">
<caption>Elements To Use in Proper Tables</caption>
<thead>
<tr>
<th>Tag </th> <th>Attributes</th> <th>Description</th>
</tr>
</thead>
<tfoot>
<tr>
<td colspan="3">* denotes optional child elements</td>
</tr>
</tfoot>
<tbody>
<tr>
<th>caption*</th>
<td>common attributes</td>
<td>A succinct description or title for the table.</td>
</tr>
...
</tbody>
</table>
Using Progressive Enhancement and Styling
The best argument for using complete semantic tables is for progressive enhancement and styling selectors. In the old paradigm, you’d need to add classes everywhere to style things; a class for the headings, a class for the footer, a class for row groups, etc. Instead, view this simple example of styling without any classes using only the elements:
table {
margin: 1em auto;
border-collapse: collapse;
}
caption { font-size: 1.2em; }
th, td {
padding: .25em;
border: 1px solid #000;
font-family: sans-serif;
}
caption, th {
color: #004900;
font-weight: bold;
text-align: left;
}
thead tr, tfoot tr { background-color: #aaa; }
thead th {
border-bottom: 3px double #000;
background-color: #ccc;
text-align: center;
}
tfoot td {
border-top: 3px double #000;
color: #333;
font-style: italic;
font-size: .8em;
text-align: right;
}
tbody th { color: #000; }
Tag | Attributes‡ | Description |
---|---|---|
* denotes optional child elements | ||
† denotes tags to be discussed in part two, next week. | ||
‡ only tag-specific attributes are included. In general common attributes are also allowed. See the W3C HTML 4.01 Attribute Table for a complete list. | ||
caption* | A succinct description or title for the table. | |
colgroup*† | span, width | A way to group columns for semantic accessibility, progressive enhancement and styling. |
col*† | span, width | A child element of colgroup, used to share attributes amongst multiple columns. |
thead* | A group of rows comprising a header for the table. | |
tfoot* | A group of rows comprising a footer for the table. | |
tbody* | A group of rows comprising the body of the table. There can be multiple tbody elements. | |
tr | A table row. If thead, tfoot, and tbody are not used, this will be a child element of the table, otherwise it is a child element of the rowgrouping elements. | |
th* | †abbr, axis, colspan, headers, rowspan, scope | A table heading. A child element of tr. Most commonly used to signify column headings when used in a thead element, but can be used as a row heading as well. |
td | †abbr, axis, colspan, headers, rowspan, scope, | Table data. A child element of tr. The most numerous element in a table, it contains data. |
Hey, we have some different stuff going on, and not a single styling class to be found! Now, that, my dear readers, is good, modern (X)HTML.
As for progressive enhancement, I’m not going to cover anything here, but things like zebra striping, column sorting, scrolling, etc. are possible with the addition of semantic elements. In fact, in the W3C documentation on HTML tables, they give the following reasons for having <thead>
and <tfoot>
elements:
This division enables user agents to support scrolling of table bodies independently of the table head and foot. When long tables are printed, the table head and foot information may be repeated on each page that contains table data.
Sounds like a good reason to use semantic tables to me!
Why?
Because it’s good development.
More importantly, having a solid semantic framework for your table makes it better for accessibility, progressive enhancement and styling. It’s the same argument for any semantic, valid code. It’s better. It makes your life easier in the long run. It’s the right thing to do.
Stay tuned for next week, when I expand on the topics we discussed today and show you how to use little-known attributes and a few more elements to really make your tables “pop.” Okay, they won’t pop, per se, but they’ll provide very important instructions for non-visual browser clients and provide a few more hooks for progressive enhancement and CSS styling.