Topic 3.1
Table Basics
In one line
An HTML table is built row by row: <table> holds rows (<tr>), each row holds cells, and a cell is either a data cell (<td>) or a header cell (<th>) that labels other cells.
Think of it like this
A school attendance register. The page is the table. Each line across, one per student, is a row. Each box on that line is a cell. The boxes along the top that say "Name", "Monday", "Tuesday" are headers: they aren't data themselves, they tell you what the boxes below them mean.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- Table
- A grid of rows and columns for data that makes sense read both across and down.
- Tabular data
- Information where each value belongs to one row and one column at the same time, like a mark for one student in one subject.
- tr
- Table row: one horizontal line of cells.
- td
- Table data: a cell that holds a value.
- th
- Table header: a cell that labels a row or a column.
- Cell
- One box in the grid, where one row and one column meet.
- Source order
- The order elements are written in the HTML file. Tables are read row by row in this order.
- Foster parenting
- The browser moving content that isn't allowed inside a table (like loose text) to just before the table.
Step by step
01Start with the table
Everything lives between <table> and </table>. On its own, an empty table shows nothing at all.
<table>
</table>02Add a header row
The first row labels the columns, so its cells are <th>. Each column will hold one kind of information: the student's name, then each subject.
<table>
<tr>
<th>Student</th>
<th>Maths</th>
<th>Science</th>
</tr>
</table>03Add data rows
Each student gets a row. The first cell names the row, so it is also a <th>: it labels the marks next to it. The marks are <td>.
Every row has the same number of cells (three here), so the columns line up.
<table>
<tr>
<th>Student</th>
<th>Maths</th>
<th>Science</th>
</tr>
<tr>
<th>Asha</th>
<td>92</td>
<td>88</td>
</tr>
<tr>
<th>Ravi</th>
<td>75</td>
<td>81</td>
</tr>
</table>04Make the grid visible
Add three CSS rules: borders on the cells, border-collapse: collapse so neighbouring borders merge into one line, and padding so the text doesn't touch the lines.
table { border-collapse: collapse; }
th, td {
border: 1px solid #999;
padding: 6px 12px;
}05Check what the browser built
Open DevTools → Elements and expand the table. You'll see a <tbody> you never wrote, wrapping your rows. That is the parser following the rule "rows live in a row group". It changes nothing visible, but it matters for CSS selectors like table > tr, which now match nothing.
Try it yourself
- 1
Add a row
In the first example, predict what
Rows:will print if you add a row forMango,Orange,₹80. Add it and run. Did the price column line up by itself? - 2
Turn data into a header
In the first example, change the
<td>around each fruit name to<th>. The names become bold and centred. Inspect one: it is now a header cell that labels its row. - 3
Remove border-collapse
Delete
border-collapse: collapse;and run. Predict first: will you see one line or two between cells? Each cell draws its own border, with 2px of space between them.
Code & diagrams
You never wrote `<tbody>`, but the browser added one. Delete the CSS tab to see a table's default look: no lines at all.
Preview
Console
Nothing logged yet.Expected console output
Rows: 4
Cells in row 1: 3
tbody elements added by the browser: 1Row by row, left to right: the same order a screen reader uses when it reads the table straight through.
Preview
Console
Nothing logged yet.Expected console output
Day > Breakfast > Lunch > Monday > Poha > Dal rice > Tuesday > Idli > RajmaThe stray sentence was written after the row, yet it appears above the table. This is foster parenting.
Preview
Console
Nothing logged yet.Expected console output
Text inside the table: I am inside a cell
Text just before the table: Oops, I am not in a cellBreak it on purpose
Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.
Break #1
Forget the tr
In the first example, delete the <tr> and </tr> around the Banana row's three cells.
Break #2
Put a heading inside the table
Add <h2>Fruit prices</h2> between <table> and the first <tr>.
Myth vs fact
Myth
th is just a bold td.
Fact
The bold look is only a default style. th means "this labels other cells", and screen readers announce it with each data cell. Making a td bold with CSS gives none of that.
Myth
You need a column element to make columns.
Fact
Columns come from the cells: the nth cell of each row forms column n. (<col> exists, but only to style or group columns; Topic 3.2.)
Myth
Tables are old-fashioned and should be avoided.
Fact
Tables were misused for page layout in the 1990s. For data, they are still the right, accessible element, and nothing else gives screen readers row and column navigation for free.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
The parser has special insertion modes for tables ("in table", "in table body", "in row", "in cell"). Foster parenting, the implied
<tbody>and implied<tr>all come from these rules in the HTML Living Standard, so every browser repairs a broken table the same way. - ▸
Because of the implied
<tbody>,table > trmatches nothing in a parsed page. Writetable trortbody > tr. In JavaScript,table.rows,row.cells,row.rowIndexandcell.cellIndexgive fast access without querying. - ▸
Table layout is costly: by default (
table-layout: auto) the browser may need every cell's content before it can fix column widths, so very large tables can lay out slowly.table-layout: fixedsizes columns from the first row and widths alone, which is faster and steadier (see the CSS course). - ▸
Closing tags
</td>,</th>and</tr>are optional in HTML: the next cell or row closes the previous one. Writing them anyway keeps the structure obvious and avoids surprises when you copy rows around.
Remember this
- 1
A table is for tabular data: information where each value belongs to both a row and a column, so reading across and reading down both make sense. "Asha's mark in Maths" is found where the Asha row meets the Maths column. If your content doesn't have that two-way meaning, it isn't a table (Topic 3.4 covers what to use instead).
- 2
The
<table>element wraps the whole thing. Inside it, each<tr>(table row) is one horizontal line. HTML has no element for a column: columns appear by themselves, because the first cell of every row lines up, then the second cell of every row, and so on. - 3
Inside a row go the cells.
<td>(table data) holds a value: a number, a word, even a link or an image.<th>(table header) holds a label for other cells. Browsers showthtext bold and centred by default, but that look is not the point:thtells screen readers "this cell names a row or column", and they read it aloud when you move between data cells. - 4
Browsers read a table in source order: the first row from left to right, then the second row, and so on (right to left in right-to-left languages like Arabic). A screen reader that reads the table straight through follows that same order, so put headers first: the header row at the top, and the row header as the first cell of each row.
- 5
The parser (the part of the browser that turns your HTML text into elements) is strict about tables. Only rows may sit directly in a table, and only cells may sit directly in a row. Text or other elements placed between cells are moved out and drawn above the table, a repair called foster parenting. The parser also wraps loose rows in a
<tbody>element for you, which you'll meet in Topic 3.2. - 6
By default a table is only as wide as its content needs, its cells have no visible borders, and there are 2 pixels of space between cells. All of that is CSS:
border,border-collapse: collapse(to merge the double lines into one) andpaddingon the cells are the usual first three rules. Don't use the oldborderattribute on<table>; it is obsolete, and CSS does the job better.
Explain it without notes
What is the difference between td and th, beyond how they look?
There is no column element in a basic table. How does a browser know which cells form a column?
What is foster parenting, and when does it happen?
When is a table the right choice for content?
Practice
Build a 3-column table of three countries with their capital and continent, with a header row.
Make the country names row headers and add borders that show as single lines.
Trade-offs
- ↔
A table gives the strongest structure for two-way data (screen reader navigation, copy-paste into spreadsheets), but it is rigid: on narrow screens wide tables need extra work (Topic 3.4).
- ↔
Leaving out optional closing tags makes the HTML shorter but harder to read and edit; most teams write them all.
Done when you can
I can build a table from
table,tr,tdandth.I can decide which cells should be headers and which are data.
I can explain the order a table is read in.
I know why the browser adds a
<tbody>and moves stray content out of a table.I can add borders, padding and
border-collapseso the grid is readable.