Skip to content

Creating Tables

Tables present data in a structured, easy-to-scan format. But tables need to be built correctly to be accessible to everyone. This tutorial covers semantic table structure and best practices.

What you’ll learn:

  • The <table>, <tr>, <td>, and <th> elements
  • Table headers, footers, and body sections
  • Accessibility with scope and headers attributes
  • Captions and summaries
  • Complex table structures
  • When to use tables (and when not to)

Prerequisites:


A table has rows and columns. Use these elements:

  • <table>: Container for the entire table
  • <tr>: Table row
  • <th>: Table header cell
  • <td>: Table data cell
Result

Key points:

  • First row uses <th> for headers
  • Data rows use <td> for cells
  • Always use <th> for header cells, never plain text in <td>

Organize your table with semantic sections:

Result
  • <thead>: Table header section (usually the first row)
  • <tbody>: Main data rows
  • <tfoot>: Summary row or footer (appears below tbody visually)

Add a caption describing the table:

Result

The <caption> should be the first child of <table>. It appears above the table and helps users understand its purpose.


For screen readers to understand table data, you need to connect headers to cells. Use the scope attribute:

Result

The scope attribute tells screen readers:

  • scope="col": This header describes a column
  • scope="row": This header describes a row
  • scope="colgroup": This header describes multiple columns
  • scope="rowgroup": This header describes multiple rows

For tables with merged cells:

Result
  • colspan="2": Cell spans 2 columns
  • rowspan="2": Cell spans 2 rows

Headers Attribute: For Very Complex Tables

Section titled “Headers Attribute: For Very Complex Tables”

For complex tables, use the headers attribute to explicitly link cells to their headers:

<table>
<thead>
<tr>
<th id="name">Name</th>
<th id="age">Age</th>
<th id="city">City</th>
</tr>
</thead>
<tbody>
<tr>
<td headers="name">Alice</td>
<td headers="age">28</td>
<td headers="city">New York</td>
</tr>
</tbody>
</table>

Each <th> gets a unique id. Each <td> lists the relevant header IDs in its headers attribute.


Here’s a realistic sports statistics table:

Result

Tables on small screens need special handling. While HTML doesn’t handle this directly, you can use data attributes:

<table>
<thead>
<tr>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
<tr>
<td data-label="Name">Alice Johnson</td>
<td data-label="Email">[email protected]</td>
<td data-label="Status">Active</td>
</tr>
</tbody>
</table>

Then use CSS to display these labels on small screens. This is more advanced and requires CSS knowledge.


Don’t use tables for layout! Use them only for actual tabular data:

<!-- Bad: Using table for layout -->
<table>
<tr>
<td>Header</td>
</tr>
<tr>
<td>Sidebar</td>
<td>Main Content</td>
</tr>
<tr>
<td>Footer</td>
</tr>
</table>
<!-- Good: Use semantic HTML and CSS -->
<header>Header</header>
<aside>Sidebar</aside>
<main>Main Content</main>
<footer>Footer</footer>

Tables are:

  • Harder to maintain
  • Difficult on mobile devices
  • Bad for accessibility
  • Slower to render

Use CSS Grid or Flexbox for layout instead.


When creating tables:

  • Use <th> for headers, never <td>
  • Add scope attribute to all <th> elements
  • Use <thead>, <tbody>, <tfoot> to organize sections
  • Add a <caption> describing the table
  • Keep tables simple—avoid complex colspan/rowspan when possible
  • Use <th scope="row"> for row headers
  • Test with a screen reader (NVDA or VoiceOver)
  • Ensure sufficient color contrast if using background colors

Create a table for your data:

Result

Try:

  1. Changing the data in the cells
  2. Adding or removing rows
  3. Adding a footer with totals
  4. Using colspan for merged cells


  • Use <table>, <tr>, <th>, <td> for table structure
  • Use <thead>, <tbody>, <tfoot> to organize table sections
  • Always use <th> for headers with scope attribute
  • Add <caption> to describe the table
  • Use colspan and rowspan sparingly
  • Make tables accessible with proper semantic structure
  • Use tables for data only, not layout

Media

Embed audio, video, and responsive images. Continue →

Metadata

Optimize with SEO meta tags and structured data. Continue →