Advanced Tables

Real data tables need more structure: header, body and footer sections; cells that span several rows or columns; and column groups for styling. This lesson covers those features and how to keep complex tables accessible.

thead, tbody and tfoot

Try it yourself
Result
  • <thead> groups the header rows, <tbody> the main data, <tfoot> summary rows like totals.
  • When a long table is printed, browsers can repeat the header and footer on every page.
  • They give CSS and JavaScript convenient hooks — e.g. sorting only the body rows.
  • A table can have several <tbody> elements to group related rows.

Even if you don't write <tbody>, the browser adds one automatically — something to remember when writing CSS selectors like table > tr, which then won't match.

Spanning columns and rows

Try it yourself
Result

colspan="2" makes a cell stretch across two columns; rowspan="2" makes it stretch down two rows. Rows below a rowspan cell need one fewer cell — notice the 11:00 row has only two cells.

Column groups

<colgroup> and <col> let you style whole columns without adding classes to every cell:

Try it yourself
Result

Only a few CSS properties apply to columns — mainly background, width, border and visibility.

Complex headers: headers and id

When a table has multiple levels of headers that scope can't describe, link each data cell to its headers explicitly:

Try it yourself
Result

The headers attribute lists the ids of every header that applies to a cell. If your table needs this, consider whether it would be clearer split into two simpler tables.

Numbers in tables

  • Right-align numeric columns so digits line up: td.num { text-align: right; font-variant-numeric: tabular-nums; }.
  • Put units in the header ("Price (€)") rather than repeating them in every cell.
  • Keep the same number of decimal places in a column.

Try it yourself

Try it yourself
Result