Learn

Learn

HTML Tables — The Basics

Build a real mental model of HTML tables: the <table> element, rows with <tr>, header and data cells with <th> and <td>, grouping with <thead> and <tbody>, labelling with <caption>, and when a table is — and is not — the right tool.

XCODXLearn · Updated

Introduction

An HTML table is the markup for presenting *tabular data* — information that is naturally two-dimensional, with values lined up in rows and columns so a reader can scan across and down to compare them. You build one with the <table> element, and inside it a small, fixed vocabulary of tags describes the grid: a table contains rows, and each row contains cells. That is the entire structure, and everything else is a refinement of it.

Why does the table model exist at all? Because some information only makes sense as a grid. A price list, a schedule, a comparison of plans, a set of measurements — each is a set of records where every record shares the same fields. A table gives every value an address: the row tells you *which record* and the column header tells you *which field*. Strip the table away and those relationships collapse into an ambiguous run of text, which is exactly the problem the element was designed to solve.

Hold one picture in your head as you read: a table is a stack of rows, and each row is a line of cells. The header cell names a column; the data cell holds a value under it. Groups such as thead and tbody label which rows are the heading and which are the body, and a caption gives the whole grid a title. Keep that stack-of-rows image and every tag below slots cleanly into it. That is the whole trick.

Lessons

1. The table element itself

Everything starts with one wrapper. The <table> element establishes the grid context; on its own it renders nothing meaningful until you put rows inside it. Think of it as the frame that holds the whole two-dimensional layout together. Nothing about a table is inferred from plain text — you declare the structure explicitly with tags, and the browser lays the grid out from that declaration. This single element is the foundation the rest of the model rests on.

<table>
  <!-- rows go here -->
</table>

2. Rows with the tr element

A table is a stack of rows, and each row is a <tr> (table row) element. The rows are ordered top to bottom exactly as you write them, and every row you add extends the grid downward by one line. A row on its own is still empty — it is a horizontal slot waiting to be filled with cells. Getting this level right matters, because the number of cells you place in each row is what fixes how many columns the whole table has.

<table>
  <tr><!-- first row --></tr>
  <tr><!-- second row --></tr>
</table>

3. Header cells and data cells

Inside each row live the cells, and there are two kinds. A <th> is a header cell — it names a column (or a row), and browsers render it bold and centred and expose it to assistive technology as a heading for the values beneath. A <td> is a data cell — the ordinary cell that holds a single value. The distinction is semantic, not cosmetic: a header cell *labels*, a data cell *contains*. Use <th> for the field names along the top and <td> for the values in the body, and screen readers can announce which column a value belongs to.

<table>
  <tr><th>Name</th><th>Age</th></tr>
  <tr><td>Ada</td><td>36</td></tr>
</table>

4. Grouping rows with thead and tbody

Once a table has a header row and several data rows, you can label their *roles* by grouping them. Wrap the heading row in a thead and the data rows in a tbody. These groups do not change the visible grid, but they tell the browser and assistive tech which part is the column heading and which is the repeating body — and they let a long table repeat its header when printed across pages. The thead holds the row of <th> labels; the tbody holds the rows of <td> values.

<table>
  <thead>
    <tr><th>Name</th><th>Age</th></tr>
  </thead>
  <tbody>
    <tr><td>Ada</td><td>36</td></tr>
    <tr><td>Grace</td><td>45</td></tr>
  </tbody>
</table>

5. Titling the grid with a caption

A <caption> is the table's title. It goes directly inside <table> as the first child, and it gives the whole grid a single accessible name so a reader — or a screen-reader user jumping between tables — knows at a glance what this data is about. A caption is not decoration you tuck outside the table in a paragraph; placed inside, it is programmatically tied to the grid, which is why it is the correct way to label tabular data.

<table>
  <caption>Team members and ages</caption>
  <tr><th>Name</th><th>Age</th></tr>
  <tr><td>Ada</td><td>36</td></tr>
</table>

6. When a table is the right tool — and when it is not

A table is the right tool for *tabular data*: records that share fields and are meant to be compared across rows and down columns. It is the wrong tool for page layout. In the early web, authors abused tables to position sidebars and navigation, and it left pages fragile, hard to restyle, and painful for assistive technology to read in a sensible order. For arranging boxes on a page, reach for modern layout systems instead; keep tables for genuine grids of data. The simplest test: if the relationship between a row and a column carries meaning, it is a table — if you only want things side by side, it is not.

That is the complete mental model. A <table> frames the grid; each <tr> is a row; a <th> labels a column while a <td> holds a value; thead and tbody mark which rows are heading and which are body; and a <caption> titles the whole thing. Reserve all of it for real tabular data. Every further feature — spanning a cell across columns with colspan, aligning columns, striping rows — is a refinement resting on that same frame.

Practice

Predict first: in the markup below, how many columns does the table have, and which cells are headers rather than data? (Answer: two columns, fixed by the two cells per row, and the top row's <th> cells are the headers.) Now edit it live — add a row, change a value, and watch the grid update:

Next steps

You have the model — now put it to work. Follow how to create a table for the step-by-step build, browse the runnable table examples for copy-paste patterns like striped rows and spanning cells, and read the value-by-value references for the <table> element and for colspan and rowspan. When your data is really a set of inputs to submit rather than a grid to display, step across to HTML Forms. Every snippet here runs in the editor.

Frequently asked questions

What is the difference between th and td in an HTML table?
A <th> is a header cell that names a column or row; browsers render it bold and expose it to assistive tech as a heading. A <td> is a data cell that holds an ordinary value. Use <th> for labels and <td> for the values beneath them.
What are thead and tbody for?
They group rows by role: thead wraps the heading row and tbody wraps the data rows. They do not change the visible grid, but they tell the browser and screen readers which rows are the header, and they let a long table repeat its header when printed.
Where does the caption go in a table?
The <caption> is the first child inside <table>. Placed there it is programmatically tied to the grid and acts as the table's accessible title, so a reader knows what the data represents.
Should I use a table for page layout?
No. Tables are for tabular data — records that share fields and are compared across rows and columns. Using them to position page elements makes pages fragile and hard for assistive technology to read; use modern CSS layout for that instead.