HTML Tables - Table Sections

Chapter 31 33 mins

Learning outcomes:

  1. What are table sections
  2. The <thead> element
  3. The <tfoot> element
  4. The <tbody> element
  5. Things to note when using these elements

Introduction

Tables are an integral part of all but the simplest of websites. In the previous chapter, we learnt about the basics of creating tables in HTML.

We learnt about the cornerstone element to represent tables in HTML, that is, <table>, and then of its constituent elements: <tr> for representing table rows, <th> for header cells, and <td> for data cells.

Now in this chapter, we shall explore table sections in HTML, used to group one or more table rows together into one single block. There are three different kinds of table sectioning elements to consider: <thead> for table headers; <tfoot> for table footers; and finally <tbody> for table body, containing the actual data.

The 3 table sections

HTML defines three elements to be used for defining sections within a <table> element.

They are as follows, abiding by the general layout of content:

  • <thead> — represents the header section of a table.
  • <tfoot> — represents the footer section of a table.
  • <tbody> — represents the body section of a table, that contains the actual data.

Each of these elements essentially acts as a group of rows (<tr> elements). In fact, in the HTML standard, these three elements are referred to as containing row groups.

In that sense, these elements are only allowed to directly contain <tr> elements. In other words, <thead>, <tfoot>, and <tbody> can NOT contain anything besides <tr>.

Speaking precisely, <thead>, <tfoot>, and <tbody> can contain <script>s as well but obviously these elements aren't rendered out on the document.

Now the first question that we should ask at this point is: Do we need sections in all tables?

Well, yes and no.

If we're creating really simple tables, like the ones we created in the previous chapter, then we shouldn't really worry about creating these sections within them; the browser can itself handle setting them up.

However, if the tables we're creating are complex and structurally detailed, we MUST use these elements to clearly distinguish between the different parts of a table, i.e. which part is a header, which one is the actual data, and so on.

The HTML standard instructs browsers to implicitly add <thead> and <tbody> anyway, so it's always a lot better to define them ourselves in the code, even if we're working with simple tables. We should be completely aware of the final structure of our HTML documents instead of the browser adding details on its own without us knowing of them.

It's worthwhile noting here that there isn't any effect of these section elements on the accessibility aspect of a table (that is, tables being read by screen readers for visually impaired users).

<thead>, <tfoot> and <tbody> mainly offer us semantic and presentational benefits:

  • Semantic in the sense that by using these elements, we clearly indicate the structure and meaning of the content of a table — it's apparent in the code as to which part of a table is its header, which one is its body, and which one is its footer.
  • Presentational in the sense that when we have a table with header and footer sections and then print the document containing the table, these sections can be printed on every single page where the table shows, for the sake of context.

And since these elements allow us to group different sets of rows, they also ease the task of styling these sets of rows.

Keep in mind that it's absolutely invalid to use <div>s for sectioning tables.

A <table> can't contain <div> sections!

Another important point to take note of while we discuss about table section elements is that it's invalid to have a <div> element inside a table for this purpose.

Recall that a <div> is a generic container that can be used to denote a group anywhere in HTML — or better to say, almost anywhere.

A <div> can, however, NOT be used directly inside a <table> element; this job is reserved exclusively for <thead>, <tfoot> and <tbody>.

Thus, the following code is structurally incorrect:

<table>
   <tr>
      <th>Programming language</th>
      <th>Release year</th>
   </tr>
<div> <!-- A <div> can't be here! --> <tr> <td>JavaScript</td> <td>1995</td> </tr> <tr> <td>Java</td> <td>1995</td> </tr> <tr> <td>C++</td> <td>1985</td> </tr>
</div> </table>

Our aim here is to group a set of rows into one single section and we use a <div> for that. But this isn't valid HTML; if we need a section, we can only use <thead>, <tfoot> or <tbody>.

But there are also some constraints on how we can use these three elements, as we shall discover throughout the rest of this chapter.

Now that we know a little bit about these table sectioning elements, let's explore each one separately in granular detail.

We'll start off with the <thead> element.

The <thead> element

The <thead> element is used to denote the header section of a <table> element.

As stated above, and restating it again here, <thead> can only contain <tr> elements directly in it (which can then obviously contain <th>s and <td>s).

Furthermore, even though <thead> has more commonality with <th> (which represents header cells), there's no necessity of having only <th>s inside a <thead>.

This is evident in the section on <thead> from the official HTML standard:

The thead element represents the block of rows that consist of the column labels (headers) and any ancillary non-header cells for the parent table element.

This definition clearly specifies that <thead> defines a block (that is, a section) of rows, and is comprised of header (<th>) and non-header (<td>) cells.

'Ancillary' here refers to non-header cells that support the primary information provided in header cells but that don't necessarily contain actual concrete data.

So what do you say now, shall we turn to an example?

In the following code, we represent a familiar table from the previous chapter, showcasing programming languages with their release date, this time with a <thead> to explicitly annotate the table's header:

<table>
<thead> <tr> <th>Programming language</th> <th>Release year</th> </tr>
</thead> <tr> <td>JavaScript</td> <td>1995</td> </tr> <tr> <td>Java</td> <td>1995</td> </tr> <tr> <td>C++</td> <td>1985</td> </tr> </table>
Programming languageRelease year
JavaScript1995
Java1995
C++1985

As you can witness in the output, <thead> has no stylistic info associated with it. Just by looking at a table, no one could tell whether it contains a <thead> or not, unless obviously we explicitly style the <thead> as such using CSS.

Now in this example, although <thead> is being used correctly, it isn't being used to its full potential. In simple tables, as this one, we're even good to go with omitting <thead> (the browser will add it on its own), although we're better off at keeping it.

Whether a table is simple or complex, a browser is bound to automatically add a <thead> in case it's not explicitly included by the developer.

Things start to become much more wishful for <thead> when we're dealing with a complex table, with an intricately detailed header.

Let's consider such a table.

In the following HTML code, we create a table to present the same three programming languages we considered in the previous examples, albeit with each one's supported paradigms:

<table border="1">
<thead> <tr> <th rowspan="2">Programming language</th> <th colspan="3">Paradigms</th> </tr> <tr> <th>Procedural</th> <th>Object-oriented</th> <th>Functional</th> </tr> </thead>
<tr> <td>JavaScript</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td>Java</td> <td>-</td> <td>Yes</td> <td>Yes</td> </tr> <tr> <td>C++</td> <td>Yes</td> <td>Yes</td> <td>Yes</td> </tr> </table>

There are two rows of headers, grouped together using a <thead>, before the actual set of data commences.

Programming languageParadigms
ProceduralObject-orientedFunctional
JavaScriptYesYesYes
Java-YesYes
C++YesYesYes

Thanks to <thead>, we're able to judge right away as to which parts of the table represent header information (the rows inside <thead>) and which ones represent actual data (the rows following <thead>).

Notice the special attributes rowspan and colspan in the first row inside the <thead>; we'll see what these do in the next chapter, HTML Tables — colspan and rowspan.

But a rough understanding won't hurt so let's get to it.

Quickly understanding colspan and rowspan

The column reading 'Programming language' needs to span the space of two rows, hence its rowspan is "2".

Similarly, the column reading 'Paradigms' needs to span the space of three columns (the ones beneath it), hence its colspan is "3".

Moving on, recall that we said above that a <thead> doesn't have to exclusively entertain only <th>s inside it (keep in mind that these <th>s obviously go inside a <tr> inside <thead>); it can also entertain <td>s for that matter.

A <td> inside a <thead> element could make sense when we want to define placeholder text for the underlying column, or possibly even explain what the column is meant for.

A <th> might not be suitable in such a case because it defines a heading which is typically read out loud by screen readers when inside a table.

As an example, consider the following code; it's our same old and gold programming languages table with the second column heading changed (previously 'Release year') and obviously more stuff added:

<table>
   <thead>
      <tr>
         <th>Programming language</th>
         <th>Release date</th>
      </tr>
<tr> <td>(The current name of the language)</td> <td>(The year of the language's first release)</td> </tr>
</thead> <tr> <td>JavaScript</td> <td>1995</td> </tr> <tr> <td>Java</td> <td>1995</td> </tr> <tr> <td>C++</td> <td>1985</td> </tr> </table>
Programming languageRelease year
(The current name of the language)(The year of the language's first release)
JavaScript1995
Java1995
C++1985

Notice the <td>s inside <thead> — each one explains the meaning of its underlying column heading.

It won't make sense to represent these <td>s as <th>s since they aren't really headings. Furthermore, it won't even make sense to include them as part of the table's actual data because they really aren't the actual data; they just explain the actual data.

To make the entire header section more prominent, and clearly distinguish between the actual data rows and the row exclusively meant to explain each column (the one we added right now), let's give it a light gray background:

<table>
   <thead style="background-color: lightgray">
      <tr>
         <th>Programming language</th>
         <th>Release date</th>
      </tr>
      <tr>
         <td>(The current name of the language)</td>
         <td>(The year of the language's first release)</td>
      </tr>
   ...
</table>
Programming languageRelease year
(The current name of the language)(The year of the language's first release)
JavaScript1995
Java1995
C++1985

Surely, now we're able to right away tell which part of the table is its description and which part is its actual data. Perfect!

All in all, always remember not to confine yourself to using <th>s only when you're within the world of <thead><td>s are just as valid.

Even the offical HTML standard has a great example (scroll down to see it) demonstrating this notion.

So now that we have a great deal of knowledge regarding <thead>, it's to time to consider the <tfoot> element.

The <tfoot> element

Given that <thead> has been covered quite extensively, there isn't that much to address in its complement, the <tfoot> element. Let's quickly understand it.

As the name suggests, the <tfoot> element is used to denote the footer section of a table.

Alright, but what can <tfoot> possibly contain in a real-world table? What exactly is a table's footer? When could we need one?

Hmm. These are all really good questions. Let's answer them in one go.

The <tfoot> element is typically used to hold summaries of the data of a table.

An example will help clarify this.

Suppose we have a table, listing the names of given items in a shopping store along with the total profits generated from selling each of them at the end of a given month, as follows:

<table border="1">
   <tr>
      <th>Item</th>
      <th>Profits ($)</th>
   </tr>
   <tr>
      <td>Wooden Table</td>
      <td>190.56</td>
   </tr>
   <tr>
      <td>Baking Pan (Small)</td>
      <td>71.05</td>
   </tr>
   <tr>
      <td>Portable Bluetooth Speaker</td>
      <td>350.93</td>
   </tr>
   <tr>
      <td>Wireless Charging Pad</td>
      <td>12.50</td>
   </tr>
</table>
ItemProfits ($)
Wooden Table190.56
Baking Pan (Small)71.05
Portable Bluetooth Speaker350.93
Wireless Charging Pad12.50

In this table, if we wish to showcase the total profits of all the items together at the end of the table, the perfect candidate to annotate this section is ... you guessed it ... <tfoot>.

That's because the total profit isn't part of the actual data; it's derived data. Likewise, it should go within the <tfoot> element.

The following snippet demonstrates the addition of <tfoot> for presenting total profits in the table above:

<table border="1">
   <tr>
      <th>Item</th>
      <th>Profits ($)</th>
   </tr>
   <tr>
      <td>Wooden Table</td>
      <td>190.56</td>
   </tr>
   <tr>
      <td>Baking Pan (Small)</td>
      <td>71.05</td>
   </tr>
   <tr>
      <td>Portable Bluetooth Speaker</td>
      <td>350.93</td>
   </tr>
   <tr>
      <td>Wireless Charging Pad</td>
      <td>12.50</td>
   </tr>
<tfoot> <tr> <td>Total:</td> <td>625.04</td> </tr> </tfoot>
</table>
ItemProfits ($)
Wooden Table190.56
Baking Pan (Small)71.05
Portable Bluetooth Speaker350.93
Wireless Charging Pad12.50
Total:625.04

The total profits value is obtained simply by adding the individual profit values in the preceding data rows.

To make this distinction, of a separate footer section, visually more promiment, we can try giving the footer a different background color:

<table border="1">
   ...
   <tfoot style="background-color: lightgray">
      <tr>
         <td>Total:</td>
         <td>625.04</td>
      </tr>
   </tfoot>
</table>
ItemProfits ($)
Wooden Table190.56
Baking Pan (Small)71.05
Portable Bluetooth Speaker350.93
Wireless Charging Pad12.50
Total:625.04

Adding more spice to this basic example, since the total deserves more emphasis than just a distinct background color, we can even mark up the content inside both the given data cells by <strong> to make them bold.

This is done as follows:

<table border="1">
   ...
   <tfoot style="background-color: lightgray">
      <tr>
         <td><strong>Total:</strong></td>
         <td><strong>625.04</strong></td>
      </tr>
   </tfoot>
</table>
ItemProfits ($)
Wooden Table190.56
Baking Pan (Small)71.05
Portable Bluetooth Speaker350.93
Wireless Charging Pad12.50
Total:625.04

Notice how we didn't replace the <td>s with <th>s for making the contained text bold. Can you reason why we didn't do so?

Well, simply because neither 'Total' nor '625.04' represents a heading; likewise, there's absolutely no point in marking them up using a <th> element.

Never write HTML solely based on how it gets presented, just like we didn't use <th> here even though it does get formatted as bold. Always follow HTML's semantics!

So what do you say, simple or not?

Besides this notion, there isn't really much to cover about <tfoot> so let's shift gears and move our attention to consider the third and final element waiting to be addressed — <tbody>.

The <tbody> element

Perhaps the most important section of a table is the one containing the actual data right? Well, it sure is. And the element that serves to wrap up all this fruitful, concrete data is <tbody>.

The <tbody> element is used to denote a body section of a table, containing actual data.

Quoting the description of <tbody> from the HTML standard:

The tbody element represents a block of rows that consist of a body of data for the parent table element...

As with the <thead> element, browsers are configured to automatically add in a <tbody> element inside a <table> when there is none present in there.

This means that if we have the code below (general form):

<table>
   <thead>
      <tr> ... </tr>
   </thead>
   <tr> ... </tr>
   <tr> ... </tr>
</table>

with a bunch of <tr> elements directly following the <thead> element, it'll automatically become something like this:

<table>
   <thead>
      <tr> ... </tr>
   </thead>
<tbody> <tr> ... </tr> <tr> ... </tr> </tbody>
</table>

The set of tr elements following <thead> are grouped together into one single <tbody>.

In order to avoid such automation from taking over, it's better to explicitly have our tables include <tbody> (just like it's better to have <thead> included as well for the exact same reason).

Let's consider a real example of using <tbody>.

We don't need to do any improvisations here, at least in the beginning, for we'll use the same tables presented in the previous sections and demonstrate the inclusion of <tbody> in them.

Consider the following table presented above without <tbody>:

<table border="1">
   <thead>
      <tr>
         <th>Programming language</th>
         <th>Release year</th>
      </tr>
   </thead>
   <tr>
      <td>JavaScript</td>
      <td>1995</td>
   </tr>
   <tr>
      <td>Java</td>
      <td>1995</td>
   </tr>
   <tr>
      <td>C++</td>
      <td>1985</td>
   </tr>
</table>

Starting onwards from the second row, all the rows of this table contain actual data. Henceforth, these rows should ideally be a part of a <tbody> element.

This is accomplished below:

<table border="1">
   <thead>
      <tr>
         <th>Programming language</th>
         <th>Release year</th>
      </tr>
   </thead>
<tbody> <tr> <td>JavaScript</td> <td>1995</td> </tr> <tr> <td>Java</td> <td>1995</td> </tr> <tr> <td>C++</td> <td>1985</td> </tr> </tbody>
</table>
Programming languageRelease year
JavaScript1995
Java1995
C++1985

Akin to <thead> and <tfoot>, <tbody> also doesn't carry any additional stylistic information with it (like a <div>).

Of course, if we wish to, we can specifically style it using some CSS styles. Let's give a light gray background to this body section of our table:

<table border="1">
   <thead>
      <tr>
         <th>Programming language</th>
         <th>Release year</th>
      </tr>
   </thead>
   <tbody style="background-color: lightgray">
      <tr>
         <td>JavaScript</td>
         <td>1995</td>
      </tr>
      <tr>
         <td>Java</td>
         <td>1995</td>
      </tr>
      <tr>
         <td>C++</td>
         <td>1985</td>
      </tr>
   </tbody>
</table>
Programming languageRelease year
JavaScript1995
Java1995
C++1985

Cool, isn't this?

Reiterating on it, it's always recommended for you to explicitly have <tbody> (and <thead>) included inside a table.

Things to note

There can be only one <thead> in a <table>

Want to have multiple <thead>s in a <table> for some weird reason? Well you simply can't!

The HTML spec clearly warns us against having multiple <thead>s inside a <table> element. An HTML table can have one and only one <thead> inside of it.

If we have more than one of it, that constitutes invalid HTML.

Henceforth, the following HTML is invalid:

<table>
   <thead>
      ...
   </thead>
<thead> <!-- Can't have another <thead>! --> ... </thead> <tbody> ... </tbody> </table>

In order to make it valid, we need to remove the second <thead> and amalgamate its contents with that of the first <thead>

While we're at it, note that this same rule applies to the <tfoot> element as well.

There can be only one <tfoot> in a <table>

Sensibly, it's also invalid to have more than one <tfoot> inside a <table>, just like the <thead> element.

An HTML table can have one and only one <tfoot> inside of it.

So, the following HTML is invalid:

<table>
   <thead>
      ...
   </thead>
   <tbody>
      ...
   </tbody>
   <tfoot>
      ...
   </tfoot>
<tfoot> <!-- Can't have another <tfoot>! --> ... </tfoot> </table>

The second <tfoot> should be removed and its contents dumped into the first <tfoot>.

<thead> must come before <tfoot> and <tbody>

An obvious rule, still necessary to mention though, is that <thead> must come before any <tfoot> and <tbody> elements inside a <table>.

As you can reason, this is quite a sensible design decision taken by HTML. Who would want to have a <thead> coming after <tbody> or <tfoot>?

So the code below is invalid, since <thead> comes after <tfoot>:

<table>
   <tfoot>
      ...
   </tfoot>
<thead> <!-- <thead> can't come over here! --> ... </thead> <tbody> ... </tbody> </table>

And so is the one below, since <thead> comes after <tbody>:

<table>
   <tbody>
      ...
   </tbody>
<thead> <!-- <thead> can't come over here! --> ... </thead> <tfoot> ... </tfoot> </table>
While <thead> must come before <tfoot> and <tbody>, if a <table> has a <caption>, it must come after that <caption>. As we learnt in the previous chapter, <caption> must be the first element inside a <table>, if included.

There can be more than one <tbody> in a <table>

Contrary to what one might assume at first, it's possible to have more than one <tbody> inside a <table> element.

This makes sense because sometimes we might want to divide the concrete data of a table into individual sections, each possibly containing its own header information (probably in the form of a <tr> with a single <th>).

Let's consider an example of a table with multiple <tbody>s.

Suppose we have our programming languages table with a handful of languages enlisted, and we now wish to distinguish them with respect to their paradigm — functional, OOP, and procedural — by having a heading before each section of languages.

This is the perfect instance of using multiple <tbody> elements, each one wrapping up a given section containing programming languages that fall under the given paradigm.

Consider the following code where we accomplish this:

<table border="1">
   <thead>
      <tr>
         <th>Programming language</th>
         <th>Release year</th>
      </tr>
   </thead>
   <tbody>
      <tr>
         <th colspan="2">Object-oriented</th>
      </tr>
      <tr>
         <td>JavaScript</td>
         <td>1995</td>
      </tr>
      <tr>
         <td>Java</td>
         <td>1995</td>
      </tr>
      <tr>
         <td>C++</td>
         <td>1985</td>
      </tr>
   </tbody>
   <tbody>
      <tr>
         <th colspan="2">Procedural</th>
      </tr>
      <tr>
         <td>C</td>
         <td>1972</td>
      </tr>
      <tr>
         <td>Pascal</td>
         <td>1970</td>
      </tr>
   </tbody>
</table>

There are two <tbody>s, each representing a different group of programming languages based on their programming paradigm, i.e. object-oriented and procedural.

Here's the output:

Programming languageRelease year
Object-oriented
JavaScript1995
Java1995
C++1985
Procedural
C1972
Pascal1970

Thanks to the allowance of multiple <tbody>s inside a <table>, we can easily represent multiple data sections.

And that's absolutely amazing!

While we're at it, it's worth reiterating that while a <table> element can have multiple <tbody>s, it can NOT have multiple <thead>s or <tfoot>s — these two elements each can only be one at max.

<tbody> can NOT come after <tfoot>

In the previous HTML specification describing the usage of <table>, the <tbody> element was allowed to come after <tfoot>.

Essentially, the idea was that a table could have a <thead> and <tfoot> right at its start while the actual data of the table wasn't available for us to render a <tbody>; once the data was available, a <tbody> would be created to showcase it.

However, in the current HTML specification, this is clearly deemed to be invalid.

That is, a <tbody> can NOT come after the <tfoot> element.

Likewise, the following HTML is invalid, as makes sense:

<table>
   <tbody>
      ...
   </tbody>
<tfoot> <!-- <tfoot> can't be here! --> ... </tfoot> <tbody> ... </tbody> </table>

So what do you say, easy points to note or not?

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage