Accessible HTML Tables: Element Attributes

The , we covered some lesser-used child elements. Between that and the first article on tables, we’re set on table elements. But what about table-specific attributes? There are quite a few, some which you may not even be familiar with. These can help non-visual user agents as well as semantics. Read on to learn more.

A good table should generally be visually designed such that a visitor can look at it and use visual cues to understand the most important data, if any, or be guided visually toward whatever data are the focus of the table. Non-visual visitors do not receive those visual cues, however. The majority of these attributes focus on non-visual user agents. They give additional information or auditory cues to allow the table to be better understood.

Please note that when I reference “the attributes of an element” in this article, I’m referring to the element/table-specific attributes. Like most elements, these can have classes, ids, and other common attributes. No need to cover those here. Additionally, I’m from the school of separate content from presentation, as you should be, and so any attributes that are visual—and thus can be set using CSS—will also be ignored for the purposes of this article. Leave a comment if you want me to cover styling tables with CSS in the future.

table element attributes

Despite this series of articles focusing on tables, we haven’t really talked about the table element, have we? It’s pretty straight forward; you put all the important bits inside the <table> tag, maybe add a class or id, and don’t think about the actual table element again. However, for good table design, we should be putting a little more thought into that. There is at least one table element-specific attribute that is smart to use.

summary
The summary attribute allows you to provide a summary of the table for non-visual user agents. Visual users may be able to look at a table and understand instantly that such and such lines total a specific amount, thanks to visual design cues, but what about non-visual visitors? By providing that sort of information in the summary attribute, you allow them to quickly gain the understanding that visual visitors have. Example:

<table summary="The data show that sales are increasing steadily, rising almost $1000 per quarter, with a year end total of $12,000 this year as opposed to $8,000 at the end of last year.">
cellspacing
This attribute controls the space in between cells—not just padding on the cells, but actual spacing between the cells, borders and all. Modern Web development generally calls for a separation of content and presentation. As such, most display attributes for table are either deprecated or better set though CSS. cellspacing is the one remaining attribute that can’t be set through CSS reliably. Truthfully, I’ve never found need for it—I always want a cell spacing of 0, which is easily accomplished through CSS by specifying border-collapse: collapse; on the table. However if you do need spacing between your cells, the closest CSS comes is a border-spacing property that is ignored by IE. cellspacing is not deprecated, so go ahead and throw it in if you really need it. Its sister attribute cellpadding is not neccessary; you can add padding to any or all cells.

Cell attributes (th and td)

In How to Use the Table Element Correctly, we explored the difference between the two cell elements, th and td. While their use in semantic tables may differ, they share many attributes.

colspan, rowspan
The two spanning attributes allow you to create a cell that spans multiple columns or rows. For instance, <td colspan="5"> would span the entire width of a 5-column table. Likewise, <th rowspan="2"> would create a heading cell that spans two rows.

It is important to note that using these two attributes requires that you leave out cells that would overlap. Here is an example:

<tr>
    <th rowspan="2">Cells</th>
    <td>data</td>
    <td>spanning, headers, axis, abbr</td>
    <td>id, class, etc</td>
</tr>
<tr>
    <td>header</td>
    <td colspan="2">Same as above</td>
</tr>

Note that there are only two cells in the second row. The first cell is not declared, as it is spanned from the row above. And the last cell is also left undeclared, because the third (second defined) spans over the final cell.

The value of these two attributes is numeric. A value of “0” is perfectly valid; this value tells the user agent to span from the current location to the end of the row group (thead, tbody, tfoot), if rowspan, or end of the current colgroup, if colspan.

axis
The axis attribute is an interesting creature. It allows for categorization of data, which enables user agents to calculate answers to queries. For instance, in a table of expenses, if you label a cell with axis="entertainment", a user can query the user agent with something like “What did I spend on entertainment”. The user agent can ascertain which data are categorized as entertainment and then calculate an answer.

Cell attributes that are mainly useful for th

There are a few attributes that are perfectly legal to use on td elements, but if used properly, they really make more sense being restricted to th elements. They are immensely helpful to non-visual user agents, especially when the contents of the table are being read out loud.

scope
Used primarily on th elements, the scope attribute designates which cells the header refers to. Allowed values are:

  • row
  • col
  • rowgroup
  • colgroup

Adding the scope attribute to the first td in a row will cause it to act like a header with non-visual user agents. But since we’re being semantic, we’d never do that, right?

abbr
This attribute is immensely useful for non-visual agents, especially auditory ones. It allows you to specify an abbreviation of the cell contents for use when reading multiple times. It mostly pertains to th elements, which are repeated before data, however it can be used for td as well. Example usage:

<th abbr="Density">Population Density (1-100)</th>

For non-visual users, the full header would be read on the first encounter, but any repetition would use the abbreviation.

Cell attributes that are mainly useful for td

The headers attribute is the sibling of scope. Whereas scope defines which data a header pertains to, headers allows for explicit indication of which headers pertain to a given data cell. Its value is a space-separated list of ids, so you must make sure to use the id attribute on any headers referenced in this way. An example:

<tr>
    <th colspan="0" id="h1">Shared Attributes</th>
</tr>
<tr>
    <th rowspan="2">Cells</th>
    <td>data cell</td>
    <td>spanning, headers, axis, abbr</td>
    <td>id, class, etc</td>
</tr>
<tr>
    <td>header cell</td>
    <td colspan="2" headers="h1">Same as above</td>
</tr>

In the above example, we see that the cell with contents “Same as above” is marked as being headed by the “Shared Attributes” header. According to the W3C, this attribute is to be used by non-visual agents, but can also be useful to visual agents through the use of CSS styling.

Other table element attributes

The attributes for other elements, such as rows, rowgroups and columns have either been covered in or are merely design aids. The latter should be done through CSS rather than HTML attributes. If you want to learn more about those or any of the attributes discussed here, the W3C Recommendation on Tables is a great place to learn virtually everything about them. It includes plenty of examples as well.

And thus concludes the series on tables. Do you have any questions, or care to expand on what I’ve said here?

Advanced HTML Tables: Columns

Last week, we discussed table basics for the year 2010 (as opposed to 1995). We set up a simple semantic table with a caption, header and footer. Today, we’re going to go over two lesser-known elements: the colgroup and col elements. I had grand plans of going into some little-known attributes for other table elements, but we’ll leave that to next week.

So, my columns feel left out

In the last article, you saw how thead, tfoot and tbody allowed for groupings of rows in a table. But often times, it’s useful to group columns as well. A couple uses I can think of include highlighting a totals column or perhaps a sales option that you want to promote. Other uses include the ability to set explicit widths for individual columns without much extra markup.

So, where do these elements go? When using column and column-group elements, you place the tags after the caption but before any row-groups or rows in the table. Modern user agents will then determine which cells belong to the appropriate column or column-group.

<table>
    <caption>Elements To Use in Proper Tables</caption>
    <colgroup span="2" width="100px">
        <col width="90px" />
        <col class="attribs" />
    </colgroup>
    <colgroup span="1" width="0*"></colgroup>
    <thead>
    ... 

colgroup: grouping columns

As you may have guessed by the “group” part of the element name, colgroup designates a structural grouping of columns. Semantically, you’re saying that the columns are related somehow.

col: sharing attributes without structural grouping

Unlike colgroup, col does not specify structure, it merely allows you to share attributes across multiple columns. In fact, for purists, one might argue that col is purely layout-driven. I’ll let you judge of that on your own.

Only two attributes?

The use of colgroup and col in HTML is limited to two attributes: span and width.

Span specifies the number of columns the group encompasses for colgroup or the attribute should apply to in the case of col. When using these two elements, make sure that the number of elements and their span attributes don’t equal more than the number of cells you have per row.

Width allows you to set the width of a column or columns in a column-group. When used in colgroup elements, remember that it specifies width of each column in the group not the total width of the grouping. If a child col also has width set it will override the parent colgroup setting. General width values are accepted, but there’s also a strange format available: the zero-asterisk (0*) value, which sets each column to be the minimum width needed to display the full cell content. You can also use an asterisk with a numerical value to designate proportional widths. For instance, if you want three columns to be set up proportionally, you could designate them as such:

<colgroup span="2" width="100px"></colgroup>
    <colgroup span="3">
        <colgroup width="1*" />
        <colgroup width="4*" />
        <colgroup width="2*" />
    </colgroup>
    <thead>
    ... 

That structure would take the total remaining width after assigning 100px to the first two columns, divide it into seven portions (1+4+2 = 7), and then apply the correct width based on portion width multiplied by number of designated portions.

Beyond these two attributes, you can use most common attributes such as id, class, align, etc.

Tell me about styling.

Here’s the drawback: colgroup and col have limited styling. You can only use four CSS attributes, and even they are limited:

  • background: you can set a background, but it is only honored if both the row and cell backgrounds are transparent.
  • border: borders work if the table has borders set to collapse (border-collapse: collapse;), at which point the borders appear based on the border conflict algorithm. If the table is set to have separated borders, no dice.
  • width: works as expected, no explicit limitations.
  • visibility: will only work with the collapse value.

But despite the limitations, these two elements can come in handy for informative tables. Let’s put it together with our table code from last time:

<table id="elements-for-tables">
    <caption>Elements To Use in Proper Tables</caption>
    <colgroup span="2" width="100px">
        <col width="90px" />
        <col class="attribs" />
    </colgroup>
    <colgroup span="1"></colgroup>
    <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>

table {
    margin: 1em auto;
    border-collapse: collapse;  /* note that this is required for using border on columns */
    }
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; }
col.attribs {
    background-color: #B6FFBD;
    border: 2px dotted #004900;
}

The result:

Elements To Use in Proper Tables
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.

Notice the funky border collapsing in the footer and that the heading background color overrides the column background color. But don’t let that limit you: be creative, and you can accomplish great feats.

Just think of how that could be useful in extremely large data sets, accounting tables, or product tables. The possibilities are endless. Next week, we’ll discuss attributes galore for semantic, accessible table creation.

How to Use the Table Element Correctly

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 table headings (th).

Of course, the bulk of the table cells are table data (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; }
Elements To Use in Proper Tables
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.