Skip to content

Complex Tables

DodaTech 3 min read

title: "Complex Tables — Making Multi-Header Tables Accessible" description: "Learn how to create accessible complex tables with multiple header rows and columns using scope, headers, and proper table structure." weight: 6 date: 2026-06-28 lastmod: 2026-06-28 tags: [accessibility, tables]


Complex tables with multi-level headers require careful use of scope, headers, and id attributes to create correct cell-to-header associations.

## What You'll Learn

How to structure tables with multiple header rows and columns, and how to use headers attributes for correct associations.

## Why It Matters

Complex tables appear in financial reports, scientific data, and product comparisons. Incorrect header associations make these tables unusable for screen reader users.

## Real-World Use

A financial table has year and quarter headers in two rows, and department and sub-department headers in two columns. The headers attribute on each cell associates it with the correct year, quarter, department, and sub-department.

## Multi-Header Table

```html
<table>
  <caption>Department budget by quarter</caption>
  <tr>
    <th id="blank" rowspan="2"></th>
    <th id="dept" colspan="2">Engineering</th>
    <th id="dept2" colspan="2">Marketing</th>
  </tr>
  <tr>
    <th id="eng-salary" headers="dept">Salaries</th>
    <th id="eng-op" headers="dept">Operations</th>
    <th id="mkt-salary" headers="dept2">Salaries</th>
    <th id="mkt-op" headers="dept2">Operations</th>
  </tr>
  <tr>
    <th id="q1" scope="row">Q1</th>
    <td headers="q1 dept eng-salary">$200K</td>
    <td headers="q1 dept eng-op">$50K</td>
    <td headers="q1 dept2 mkt-salary">$150K</td>
    <td headers="q1 dept2 mkt-op">$40K</td>
  </tr>
  <tr>
    <th id="q2" scope="row">Q2</th>
    <td headers="q2 dept eng-salary">$210K</td>
    <td headers="q2 dept eng-op">$55K</td>
    <td headers="q2 dept2 mkt-salary">$160K</td>
    <td headers="q2 dept2 mkt-op">$45K</td>
  </tr>
</table>

Row Group Headers

<table>
  <caption>Employee data by region</caption>
  <tr>
    <th id="region" rowspan="2">Region</th>
    <th id="name" rowspan="2">Name</th>
    <th id="role" colspan="2">Position</th>
  </tr>
  <tr>
    <th id="title" headers="role">Title</th>
    <th id="level" headers="role">Level</th>
  </tr>
  <tr>
    <th id="west" scope="rowgroup" rowspan="2">West</th>
    <th id="alice" scope="row">Alice</th>
    <td headers="west alice title">Engineer</td>
    <td headers="west alice level">Senior</td>
  </tr>
</table>

Common Mistakes

1. Missing rowspan on row group headers

When a header spans multiple rows, use rowspan on the th element.

2. Inconsistent headers references

Every cell in the same column must reference the same set of header ids.

3. Circular headers references

Headers that reference each other create infinite loops. Ensure references are one-directional.

4. No scope="rowgroup" for grouped row headers

When a row header spans multiple rows, use scope="rowgroup".

5. Too many headers references

Keep header associations to 3-4 references per cell. Too many references confuse users.

Practice Questions

1. What attribute spans a header across multiple rows? rowspan on the th element extends the header across multiple rows.

2. How do you associate a cell with a header two levels up? Use the headers attribute with space-separated ids: headers="top-header mid-header current-header".

3. What scope value is used for a header that labels a group of rows? scope="rowgroup" indicates the header labels a group of rows.

Challenge: Create a complex table with two header rows and two header columns. Use headers attributes for all data cells.

FAQ

How many header levels are too many?

More than three levels of headers is typically too complex. Consider splitting into multiple tables.

Do I need headers on cells in the header rows?

Yes. Header cells that have parent headers also need headers attributes to associate with the higher-level header.

Can I use CSS display:grid instead of tables?

CSS grid does not provide the same semantics. Use HTML tables for data that has row/column relationships.

How do I verify headers associations?

Use browser dev tools to inspect the headers attribute. Use screen reader table navigation to verify announcements.

Should I simplify complex tables?

Yes. If a table needs more than two header levels, consider splitting it into multiple simpler tables.

Mini Project

Create a complex table with three header rows (year, quarter, month) and two header columns (department, team). Use headers to create all associations.

What's Next

Learn how to provide a Summary Description for tables using aria-describedby.

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro