HTML tables exist for one specific job: displaying tabular data — rows and columns of related values, like a pricing comparison or a spreadsheet of results. They have a bad reputation from the early 2000s, when developers used them to build entire page layouts (columns, sidebars, navigation bars) because CSS layout tools were weak at the time. That era is long over, but tables themselves remain exactly the right tool whenever your content genuinely is a grid of data.
Basic Table Structure
<table>
<thead>
<tr>
<th>Plan</th>
<th>Price</th>
<th>Storage</th>
</tr>
</thead>
<tbody>
<tr>
<td>Basic</td>
<td>$5/mo</td>
<td>10GB</td>
</tr>
<tr>
<td>Pro</td>
<td>$15/mo</td>
<td>100GB</td>
</tr>
</tbody>
</table>
This renders a two-row pricing table with a bold header row reading "Plan / Price / Storage." <table> is the container, <thead> groups the header row(s), <tbody> groups the data rows, <tr> is a table row, <th> is a header cell (bold and centered by default), and <td> is a regular data cell.
When a Table Is the Right Choice — and When It Isn't
Use a table when the data genuinely has rows and columns that relate to each other — a schedule, a price list, search results with multiple sortable attributes. Don't use a table when you actually want a page layout: a three-column homepage, a sidebar next to an article, a navigation bar. For layout, Flexbox and CSS Grid are both far more flexible and were purpose-built for exactly that job.
A good rule of thumb: if you'd naturally describe the content as "a table of X," it should be a table. If you're reaching for a table only because it lines things up visually, reach for CSS Grid instead.
Spanning Cells with colspan and rowspan
<tr>
<td colspan="2">Spans two columns</td>
<td>Normal cell</td>
</tr>
This renders the first cell stretched across the width of two normal columns, pushing the third cell further right than it would otherwise sit. colspan merges a cell across multiple columns; rowspan works the same way but merges a cell down across multiple rows. Both are handy for things like a header that groups several sub-columns under one label.
Captioning a Table
A <caption> element, placed right after the opening <table> tag, gives the table a visible title and is announced by screen readers before the table's contents — useful when a page has more than one table and the visual context alone isn't enough to tell them apart.
