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!

1 Like

This is so helpful.
To be clear, <th> is not needed in when <thead> is referenced, only the <td>?

Not sure I understand your question.

@mtf so, if I understood correctly, the <tbody> element should contain all the table data and all the column/row headings and the <thead> element should contain the table heading.

Essentially, yes. We don’t want to describe the table in the data body, but only describe the data, itself. The table heading describes the table, and the footer describes the finer details.


@mtf, so the example here doesn’t actually require a <thead> at all, it only needs a <tbody> that wraps everything

In stripped down form, the TBODY would suffice, with the first row being TH elements. Structurally, though, I’d have to walk back my earlier comment and agree that the example is perfectly valid, and user agents will understand (we would hope) the role of the header elements.

Personally, I see a disconnect that visually doesn’t show, but from a user agent’s standpoint of relating the heading cells to their data in the column beneath they belong in the same parent container, meaning the body, not the grandparent, the table. A user agent will perfectly understand what a TH is, and know it is not part of the data in any way more than its scope would suggest.

In short, let the THEAD act as a table header, not a TH. Information significant to the overall table belongs there, and column headings are not part of that. But here (this course) we’re learning more the construction techniques and less the theory and conjecture. It’s HTML–what can go wrong?

1 Like

@mtf, I am a little confused as I checked the table mdn docs and I saw that they are using the <thead> element as a container for all the column headings.

Like I said, it is all valid HTML. Don’t let be confused. Opinions vary.

Take for instance the LABEL element in relation to an INPUT control. When it is not wrapping the control it needs to declare the control it is scoped to so must have a for attribute. When THs are written in the THEAD they should rightly have scope attributes. When written in the TBODY the attributes are not needed.

Hi there! The lesson just before was alluding to being able to scroll through large data samples and still be able to understand what you were looking at. That’s when we are introduced to the < tbody > (table body) element.

I thought they introduced the < thead > (table head) element, not just for the actual heading of the table (in your example, Weekend Schedule), but also for the < th >s (the table headings–i.e., Saturday and Sunday).

This, if I understand it correctly, would allow you to scroll through pages of data in a table and still be able to read the head (Weekend Schedule), but also the table headings (Saturday and Sunday). Am I reading too much into this? It wouldn’t be super helpful to just be able to see the name of the table, I would forget which column was about what–is this date Saturday or Tuesday?

So it would make sense to put the < th >s inside the < thead >, no?

If you have a line printer connected, create a table with say, 200 rows.

Unfortunately I cannot play along. I suspect the printer driver will see the THEAD as repeated on each new printed page. For that reason. the headings should be in that segment. Any previous opposition by me to that norm should be disregarded.