HTML Tables: Rows, Cells, Headers, and Accessible Markup

Published Updated

An HTML table gives the browser the kind of grid you would recognize from a spreadsheet. Each row describes one record, each column describes one property, and the browser keeps those relationships connected as the table grows.

Tables are one part of HTML page structure. Use them for data whose rows and columns have meaning, not to position page sections.

<table>
  <tr>
    <td>Espresso</td>
    <td>$3.00</td>
  </tr>
  <tr>
    <td>Cold brew</td>
    <td>$4.50</td>
  </tr>
</table>

How Does an HTML Table Work?

An HTML table contains rows made of header or data cells. The table structure tutorial starts with that basic grid.

The table element wraps the complete grid. A tr creates one table row, while each td adds a data cell to that row. Columns appear because cells in the same position line up across rows, just as spreadsheet cells line up under the same column letter.

The first example has two rows with two cells each. Drink names form the first column and prices form the second, even though HTML has no separate column element for placing those values.

How Do You Add HTML Table Headers?

Use th for HTML table headers and scope to identify the row or column each header labels. A bold td may look like a header but does not have the same meaning.

<table>
  <tr>
    <th scope="col">Drink</th>
    <th scope="col">Price</th>
  </tr>
  <tr>
    <th scope="row">Espresso</th>
    <td>$3.00</td>
  </tr>
  <tr>
    <th scope="row">Cold brew</th>
    <td>$4.50</td>
  </tr>
</table>

The drink cells now use scope="row" because each one labels the value beside it. Browsers can infer scope in a simple table, but explicit values help assistive technology, such as screen readers and similar tools, associate each price with the correct row and column headers.

How Do You Name and Group an HTML Table?

Name an HTML table with a caption as its first child. Group header rows in thead, data rows in tbody, and a total or summary in tfoot. The headers and captions guide explains each part.

<table>
  <caption>Coffee sales for Saturday</caption>
  <thead>
    <tr>
      <th scope="col">Drink</th>
      <th scope="col">Cups sold</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Espresso</th>
      <td>18</td>
    </tr>
    <tr>
      <th scope="row">Cold brew</th>
      <td>12</td>
    </tr>
  </tbody>
  <tfoot>
    <tr>
      <th scope="row">Total</th>
      <td>30</td>
    </tr>
  </tfoot>
</table>

The caption tells readers what the numbers describe before they enter the grid. The row groups also provide stable hooks for CSS and JavaScript, while keeping the source easy to inspect.

How Do You Merge HTML Table Cells?

Use colspan to merge HTML table cells across columns and rowspan to span rows. Count the slots each cell occupies; the spanning cells guide walks through that count.

<table>
  <caption>Weekend coffee sales</caption>
  <colgroup span="1"></colgroup>
  <colgroup span="2"></colgroup>
  <thead>
    <tr>
      <th scope="col" rowspan="2">Drink</th>
      <th scope="colgroup" colspan="2">Cups sold</th>
    </tr>
    <tr>
      <th scope="col">Saturday</th>
      <th scope="col">Sunday</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Espresso</th>
      <td>18</td>
      <td>21</td>
    </tr>
    <tr>
      <th scope="row">Cold brew</th>
      <td>12</td>
      <td>15</td>
    </tr>
  </tbody>
</table>

The two colgroup elements define the single Drink column and the two-column sales group, so scope="colgroup" explicitly associates Cups sold with both day columns. Every body row still fills three grid slots. Spanning changes the shape of the header without leaving gaps in the data beneath it.

How Do You Style an HTML Table?

Style HTML table cells with CSS borders, padding, and text alignment. Use border-collapse: collapse on the table for shared borders. For data coming from a spreadsheet, the CSV-to-HTML tutorial creates this markup automatically.

Keep classes focused on the table's visual role, such as sales-table, and leave the row and column meaning in the HTML elements. A common first rule is border-collapse: collapse, which makes adjacent cell borders share a single line.

<table class="sales-table">
  <!-- caption, row groups, rows, and cells -->
</table>

<style>
  .sales-table {
    border-collapse: collapse;
  }
</style>

The CSS guide covers table widths, cell spacing, wrapping, and small-screen layouts.

How Do You Make an HTML Table Accessible?

Make an HTML table accessible with meaningful th headers, appropriate scope values, and a concise caption. These describe the relationships a sighted reader follows across rows and columns. Test complex tables with the assistive technology your audience uses.

HTML tables should represent meaningful rows and columns of data. Using table cells to position a sidebar, hero, or form adds relationships that the content does not have. CSS layout keeps visual placement separate from the document's data structure.

Common Pitfalls & Debugging

Headers Without Explicit Scope

A browser can infer the direction of simple headers, although some assistive technology may not make the same association reliably. Add scope="col" or scope="row" to each th, then check that every data cell has the headers you expect.

Uneven Cell Counts

A short row leaves an empty slot, which can shift values away from their intended headings. Count the occupied slots in each row, including any slots claimed by colspan or rowspan. Developer tools make the mismatch easier to spot when the source looks balanced.

Tables Used for Page Layout

Layout tables often look acceptable on a wide screen, then read as meaningless data grids to assistive technology and become difficult to rearrange on narrow screens. Replace the layout table with semantic page elements and handle their placement in CSS.

An Unexpected tbody in the DOM

Browsers may insert a tbody around rows written directly inside table. JavaScript selectors such as table > tr then fail because each row is a child of the inserted body. Write tbody explicitly and target the structure that appears in the DOM.

Frequently Asked Questions

When should you use an HTML table instead of CSS Grid?

Use an HTML table when the content has meaningful row and column relationships, such as prices, schedules, or results. Use CSS Grid when the columns exist only to arrange page sections or components visually.

How do you make an HTML table responsive?

Make a wide HTML table responsive by placing it in a container with overflow-x: auto, while keeping headers and cell relationships intact. Let text wrap where it stays readable, and check that keyboard users can reach and scroll the container.

Are layout tables ever acceptable in modern HTML?

Some HTML email templates still use layout tables because older mail clients support limited CSS. Keep the structure as simple as the email permits, add presentation roles where appropriate, and test it with the actual mail clients and assistive technologies your audience uses.

Does every HTML table need thead, tbody, and tfoot?

HTML tables do not require all three row groups. Use thead for header rows, tbody for the main data, and tfoot when you have a footer or summary. Explicit groups make styling and scripting easier even in a small table.

Can an HTML table compare just two or three items?

An HTML table can compare two or three items when the columns represent shared properties such as price and size. Choose a table because the data has row and column relationships, not because it reaches a minimum row count.

Does a table need column widths, or can the browser size columns automatically?

A browser sizes table columns automatically from cell content and available space unless CSS overrides it. Specify widths only when a design requires a particular proportion; automatic sizing keeps a data-driven table readable without extra CSS.

Sources

  1. [1]
    The Table element
    (developer.mozilla.org)
  2. [2]
    HTML table accessibility
    (developer.mozilla.org)
  3. [3]
    The Table Body element
    (developer.mozilla.org)
  4. [4]
    border-collapse
    (developer.mozilla.org)