📊 Phase 4 · Tables & Forms🟡 IntermediateModule 05
Table Structure
Course Progress46% complete
A complete semantic table isn't just rows and cells — it has a head, body, and foot, just like a document. Structural elements like
<thead>, <tbody>, and <tfoot> group rows by purpose, enable independent scrolling, and help screen readers navigate complex data tables correctly.
Section 1
thead, tbody, tfoot
These three sectioning elements divide a table into logical regions:
thead
Column headers — repeats on every printed pagetbody
Main data rows — can be multiple tbody sectionstbody
Second tbody section (optional, for grouping)tfoot
Summary/totals row — may scroll with body in CSSHTMLFully structured table
<table> <caption>Q3 Sales Report</caption> <thead> <tr> <th scope="col">Product</th> <th scope="col">Units Sold</th> <th scope="col">Revenue</th> </tr> </thead> <tbody> <tr> <th scope="row">HTML Course</th> <td>1,240</td> <td>£12,400</td> </tr> <tr> <th scope="row">CSS Course</th> <td>980</td> <td>£9,800</td> </tr> </tbody> <tfoot> <tr> <th scope="row">Total</th> <td>2,220</td> <td>£22,200</td> </tr> </tfoot> </table>
Section 2
The scope Attribute
The scope attribute on <th> tells screen readers whether a header applies to a column, row, or group of columns/rows. It dramatically improves accessibility on complex tables.
| scope value | Meaning | Example |
|---|---|---|
col | Header for the column below it | Column labels in thead |
row | Header for the row it's in | Row label as first cell |
colgroup | Header for a group of columns | Spanning grouped header |
rowgroup | Header for a group of rows | Group label spanning rows |
♿
scope makes tables screen-reader friendly
Without
scope, screen readers must guess which headers apply to which cells. With it, a screen reader can announce "Product: HTML Course, Units Sold: 1,240" — the user always knows the context of each value.Section 3
Column Groups
The <colgroup> element (and its children <col>) let you apply styling to entire columns without adding classes to every cell. Place it immediately after the <caption> and before <thead>.
HTML + CSScolgroup and col
<table> <caption>Browser Support</caption> <!-- style columns without touching every td --> <colgroup> <col style="width: 40%"> <!-- Feature column --> <col style="background: rgba(45,232,192,.05)"> <!-- Chrome --> <col> <!-- Firefox --> <col> <!-- Safari --> </colgroup> <thead> <tr> <th scope="col">Feature</th> <th scope="col">Chrome</th> <th scope="col">Firefox</th> <th scope="col">Safari</th> </tr> </thead> <!-- tbody rows ... --> </table>
Section 4
Long Table Scrolling
For long data tables on mobile, wrap the table in a container with overflow-x: auto to allow horizontal scrolling without breaking the page layout. This is far better than a table that overflows off-screen.
HTML + CSSResponsive table wrapper
<!-- HTML --> <div class="table-wrap"> <table> <!-- ... lots of columns --> </table> </div> /* CSS */ .table-wrap { overflow-x: auto; /* horizontal scroll */ -webkit-overflow-scrolling: touch; /* smooth iOS scroll */ border-radius: 8px; border: 1px solid #e2e8f0; }
🧩 Quick Check — Lesson 16
5 questions · instant feedback
1. Which element wraps the column header row(s) of a table?
2. What does scope="col" on a <th> element tell screen readers?
3. Where should tfoot content appear visually?
4. What is the purpose of <colgroup> and <col>?
5. How do you make a wide table scroll horizontally on mobile?
🏆
Quiz Complete!
Table structure done! Last table topic: colspan & rowspan.
Lesson 16 Challenge
Code exercise · 15 min
Build a fully structured data table with thead, tbody, and tfoot.
Create a monthly budget table with these columns: Category, Budget, Actual, Difference.
1. Use
2. Use
3. Use
4. Use row headers
5. Use
6. Wrap in a
Create a monthly budget table with these columns: Category, Budget, Actual, Difference.
1. Use
<caption> with a descriptive title2. Use
<thead> with <th scope="col"> for all column headers3. Use
<tbody> for at least 4 spending categories (Rent, Food, Transport, Entertainment)4. Use row headers
<th scope="row"> for each category name5. Use
<tfoot> for the totals row6. Wrap in a
div.table-wrap with overflow-x: auto
Show hints
- tfoot can appear in source before tbody — it'll still render at the bottom
- scope="col" on column headers, scope="row" on row headers
- The totals row uses th for the label and td for the sums
- Style thead differently from tbody for visual hierarchy