Tables

Tables are the most frustraiting thing that I code, but here below I think I've listed out every type of tables. Screen shots of the rendered tables is yet to come.

Header cells

Header cells must be marked with <th>, and data cells with <td> to make tables accessible. For more complex tables, explicit associations may be needed using scope, id and headers attributes.

Tables with one header

Table with header cells in the top row only

If the table is fairly small and the data is distinctly different in each column (the relationship between the header and data cells are evident) then this is acceptable.

<table>
    <tr>
        <th>Date</th>
        <th>What's happening?</th>
        <th>Where?</th>
    </tr>
    <tr>
        <td>17 August</td>
        <td>Going to get coffee</td>
        <td>At a cat cafe!</td>
    </tr>
    […]
</table>

Table with header cells in the first column only

Now we are putting the header column on the left. Also in this situation, it is only acceptable to use this code because it is such a small table.

<table>
    <tr>
        <th>Date</th>
        <td>1 April</td>
        <td>17 August</td>
        <td>20 April</td>
    </tr>
    <tr>
        <th>What's happening?</th>
        <td>Going to get coffee</td>
        <td>Going for a run</td>
        <td>Going to get a tattoo!</td>
    </tr>
    <tr>
        <th>Where ?</th>
        <td>At a cat cafe</td>
        <td>Outside</td>
        <td>In prison</td>
    </tr>
</table>

Table with ambiguous data

Now we have data (first name, last name, city) that can't be distinguished from one another without knowing which header each corresponds to. The scope attribute with the value col defines the direction of the header cells and associates them with the corresponding data cells. The scope attribute is also needed for larger tables with one header row or column.

<table>
  <caption>Teddy bear collectors:</caption>
  <tr>
    <th scope="col">Last Name</th>
    <th scope="col">First Name</th>
    <th scope="col">City</th>
  </tr>
  <tr>
    <td>Bunny</td>
    <td>Bugs</td>
    <td>NY</td>
  </tr>
  <tr>
    <td>Rabbit</td>
    <td>Peter</td>
    <td>Chicago</td>
  </tr>
  <tr>
    <td>Rabbit</td>
    <td>Roger</td>
    <td>LA</td>
  </tr>
</table>

Tables with two headers

For this type of tables we use the <ht> element to identify the header cells and the scope attribute to declare the direction of each header. The scopeattribute can be set to row or col to denote the that a header applies to the entire row or column, respectively.

Additionally, you can use the <caption> element to identify the table in a document. This is particularly useful for screen reader users browsing the web page in "table mode" where they can navigate from table to table.

Table with header cells in the top row and first column

All header cells are marked up as the <th> cells with scope attributes added.

In the header row, the col value for scope associates each header cells with the data cells in the column. In the header column, the row calue associates the individual headers with their rows. Without this information, some users would not easily understand the relationship between header and data cells.

<table>
  <caption>Delivery slots:</caption>
  <tr>
    <td></td>
    <th scope="col">Monday</th>
    <th scope="col">Tuesday</th>
    <th scope="col">Wednesday</th>
    <th scope="col">Thursday</th>
    <th scope="col">Friday</th>
  </tr>
  <tr>
    <th scope="row">09:00 - 11:00</th>
    <td>Closed</td>
    <td>Open</td>
    <td>Open</td>
    <td>Closed</td>
    <td>Closed</td>
  </tr>
  <tr>
    <th scope="row">11:00 - 13:00</th>
    <td>Open</td>
    <td>Open</td>
    <td>Closed</td>
    <td>Closed</td>
    <td>Closed</td>
  </tr>
  […]
</table>

Table with an offset column of header cells

In this example the row header cells are in the second rather than in the first column.

The scope of the header cells in the top row is set to col. By using the row value for scope assigns the header cells in the second column to the data cells on the left and the right of the individual header cell.

[…]
<tr>
  <td>215</td>
  <th scope="row">Abel</th>
  <td>5</td>
  <td>2</td>
  <td>0</td>
  <td>0</td>
  <td>0</td>
  <td>3</td>
</tr>
[…]

Tables with irregular headers

These examples are with header cells that span multiple columns and/or rows. Several elements and attributes can be used to degine the structure and relationships of the header and data cells.

For example, a header cell that spans three columns should be associated with corresponding data cells in the column group. This can be done by setting the scope attribute of the header cell to the value colgroup. The same principle applies to header cells spanning multiple rows. In this case, they are associated with by using the value rowgroup in the scope attribute.

However, before making these associations, the structure of such groups of columns and rows needs to be defined in the table markup:

  • A column group is defined using the <colgroup> element.
  • A row group is defined by the <thead>, <tfoot> and <tbody> elements.
  • <thead> and <tfoot> elements can be used once in a table.
  • A table can have any number of <tbody> elements that each defines a row group.

Table with two tier headers

Here there are two pairs of column headers. Each pair of column headers, "Produced" and "Sold" is associated with a first-level header that identifies the pair: "Mars" and "Venus". These first-level headers are made to span two columns by using the colspan element instead of that number of <col> elements, and the number of columns spanned is noted in the span attribute.

Also, the value of the scope attribute in the first-level headers is set to colgroup so that it is associated with the entire group of columns. The second-level headers only apply to the corresponding column, so the scope attribute is set to col.