What is the difference between thead and th?


If th and thead are both headings in a table, what is the difference between them?


thead is essentially a box to hold your headings for the table. It is used along with tbody and tfoot to make up the entirety of a table - header, body, footer.
On the otherhand, th is a single heading element.

In this example given in the instructions for the table head exercise, the whole top row is the thead for the table. The bolded bits of text are each th elements.


The example above is a little bit misleading. The top row is technically part of the table body, not the header.

  <caption>The caption describes the table.</caption>
    <tr><th colspan="3">Weekend Schedule</th></tr>
    <tr><td colspan="3"><p>The fine print or summary of the table</p></td></tr>
      <td> </td>
      <th scope="col">Saturday</th>
      <th scope="col">Sunday</th>
      <th scope="row">Morning</th>
      <td rowspan="2">Work</td>
      <td rowspan="3">Relax</td>
      <th scope="row">Afternoon</th>
      <th scope="row">Evening</th>

Note: The caption is a required element under accessibility guidelines.

The above comes together with a simple style sheet…

body {
  font-size: 100%;
table {
  border-collapse: separate;
  border: 1px solid red;
  width: 50%;
  margin: 0 auto;
  font-size: 1.5em;
th, td {
  border: 1px solid green;
  width: 33%;
td {
  text-align: center;
tfoot p,
caption {
  font-size: 0.7em;


table example


Thanks for the input and the extra example! I was working off of the example in the instructions here, where the thead does contain the blank, “Saturday”, and “Sunday” elements.


Ah, I see. A misleading lesson example that can snowball. Tables are very flexible, thanks to the nature of HTML, though as we can see above there is a best practice approach that takes into account strict semantics.

In the example of the lesson column headings are being treated as header of the table. That results in an overlap of semantics. THEAD is not a column header, but at TABLE header.

TH is geared to both column headings and row headings, which roles are declared in the scope attribute. Technically speaking, the THEAD does not require a TH, just a TD. There is no need to define scope since its scope is the entire table.

<tr><td colspan="3">Weekend Schedule</td></tr>

Only thing with this may be the added code weight of CSS to style the element. TH has default styles that fit in perfectly here. That’s what is known as a style cheat. Mind, the only inherited property that is does not already have is font-weight. The default style actually looks better, imho.


Meant to mention this earlier, notice that in the top body row the first element is a TD, not a TH. Being empty it has no role but space holder.Headings are not data, per se, but assuming they are, then a heading for that column would be appropriate.


On the basic structure of the HTML we must place the element before the element, in order to provide the browser timely information of how the code should be rendered.

Does this “order” not apply when declaring the head, body and footer of a table? I’m asking because even though the footer was declared before the body in the HTML code you shared with us, the final table looks ok.



The browser spec is backward compatible so that legacy code will still render as before. What we see above is actually HTML 4 markup, and that was how <tfoot> and <tbody> were written, by the spec of the day.

HTML5 has deemed this obsolete for reasons of accessibility, but as we see, since HTML5 is not much removed from HTML 4, it still works. For the purposes of validation and passing accessibility checks, they should be written in the natural order.

Error: Element tbody not allowed as child of element table in this context. (Suppressing further errors from this subtree.)

From line 14, column 11; to line 15, column 9

  </tfoot>↩  <tbody>↩    <

thank’s for the instruction i was a bit conffused before i saw these one.

thanks @mtf for the explanation… it makes more sense and also easier to undertand! :+1:

1 Like

Actually, I noticed that scope does not do much, added or not. I added in one column but did not add in another but same table head and it worked perfectly.

Your explanation makes this lesson so much easier to understand! Thanks!