BlogTutorial
Tutorial

HTML Table Tutorial: Rows, Columns, Colspan & Rowspan Explained

HTML tables are one of the most useful — and most misunderstood — elements in the language. Used correctly, they present tabular data clearly and accessibly. Used incorrectly (for page layout, for example), they cause maintenance headaches and accessibility failures. This guide covers everything from basic table structure to merging cells with colspan and rowspan. Use our HTML table generator to build tables visually while following along.

Basic Table Structure

An HTML table is built from four core elements:

<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Role</th>
      <th>Location</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alex</td>
      <td>Developer</td>
      <td>London</td>
    </tr>
  </tbody>
</table>
  • <table> — the container element
  • <thead> — groups the header row(s)
  • <tbody> — groups the data rows
  • <tr> — a table row
  • <th> — a header cell (bold and centred by default; announced to screen readers as a header)
  • <td> — a data cell

Always separate <thead> from <tbody>. It allows browsers to scroll the body independently of the header on long tables, enables proper printing (headers repeat on each printed page), and makes the structure semantically meaningful to assistive technologies.

Colspan: Merging Columns

The colspan attribute makes a cell span across multiple columns. When you set colspan="2", remove the adjacent cell that it covers — the total cell count per row must remain consistent:

<tr>
  <th colspan="2">Full Name</th>
  <th>Location</th>
</tr>
<tr>
  <td>Alex</td>
  <td>Johnson</td>
  <td>London</td>
</tr>

Rowspan: Merging Rows

rowspan makes a cell span multiple rows. The cell appears in the first row; subsequent rows omit the cell it covers:

<tr>
  <td rowspan="2">EU Region</td>
  <td>Germany</td>
</tr>
<tr>
  <td>France</td>
</tr>

Styling HTML Tables with CSS

By default, tables have separated borders. Use border-collapse: collapse to merge adjacent cell borders into a single border:

table {
  border-collapse: collapse;
  width: 100%;
}
th, td {
  padding: 10px 14px;
  border: 1px solid #e2e8f0;
  text-align: left;
}
thead th {
  background: #1e3a8a;
  color: white;
}
tbody tr:nth-child(even) {
  background: #f8fafc;
}

Accessibility: scope and caption

Add a <caption> element immediately after <table> to give the table a visible title. Screen readers announce it before reading the table content. Add scope="col" to header cells to explicitly associate them with their column:

<table>
  <caption>Q1 Sales by Region</caption>
  <thead>
    <tr>
      <th scope="col">Region</th>
      <th scope="col">Sales</th>
    </tr>
  </thead>
  ...
</table>

Making Tables Responsive

Wide tables overflow their containers on small screens. Wrap them in a scroll container:

<div style="overflow-x: auto;">
  <table>...</table>
</div>

This allows the table to scroll horizontally on mobile without breaking the page layout. After building your table structure, run it through the HTML validator to confirm the cell counts are consistent across all rows — mismatched cell counts are the most common table error and cause unpredictable rendering across browsers.

When NOT to Use Tables

Tables are for tabular data — information where rows and columns have meaning. Never use tables for page layout. CSS Grid and Flexbox have made table-based layouts completely unnecessary, and table layouts are a significant accessibility problem: screen readers read table cells in DOM order, which may not match the visual reading order your layout implies.

← How to Clean HTML from Word Next: HTML vs Markdown →