Tables with Colspan and Rowspan

Create accessible tables with colspan and rowspan using proper id and headers attributes to maintain context for screen reader users.

advanced
1.3.1 Info and Relationships (Level A)4.1.2 Name, Role, Value (Level A)2.4.6 Headings and Labels (Level AA)
❌

The Bad (Inaccessible)

<table>
  <tr>
    <td colspan="2">Q1 Sales</td>
  </tr>
  <tr>
    <td>Product A</td>
    <td>$10,000</td>
  </tr>
  <tr>
    <td rowspan="2">Total</td>
    <td>$10,000</td>
  </tr>
  <tr>
    <td>$15,000</td>
  </tr>
</table>
βœ…

Accessibility-Ready Code

<!-- Gold Standard: Colspan/rowspan with proper headers -->
<table class="spanning-table">
  <caption>
    Quarterly Sales Report by Region
    <span class="sr-only">
      - Sales figures with regional totals and quarterly summaries
    </span>
  </caption>

  <thead>
    <!-- Header row with column spanning -->
    <tr>
      <th scope="col" id="region">Region</th>
      <th scope="col" id="q1" colspan="3">Q1 2024</th>
      <th scope="col" id="total">Total</th>
    </tr>

    <!-- Sub-headers under colspan -->
    <tr>
      <th scope="col" headers="region"></th>
      <th scope="col" id="jan" headers="q1">January</th>
      <th scope="col" id="feb" headers="q1">February</th>
      <th scope="col" id="mar" headers="q1">March</th>
      <th scope="col" headers="total"></th>
    </tr>
  </thead>

  <tbody>
    <!-- East Region (spans 2 rows) -->
    <tr>
      <th scope="row" id="east" rowspan="2">East Region</th>
      <td headers="east q1 jan">$45,000</td>
      <td headers="east q1 feb">$52,000</td>
      <td headers="east q1 mar">$48,000</td>
      <td headers="east total">$145,000</td>
    </tr>

    <!-- Second row of East Region (row header spans from above) -->
    <tr>
      <td headers="east q1 jan">$50,000</td>
      <td headers="east q1 feb">$55,000</td>
      <td headers="east q1 mar">$60,000</td>
      <td headers="east total">$165,000</td>
    </tr>

    <!-- West Region -->
    <tr>
      <th scope="row" id="west" rowspan="2">West Region</th>
      <td headers="west q1 jan">$38,000</td>
      <td headers="west q1 feb">$42,000</td>
      <td headers="west q1 mar">$45,000</td>
      <td headers="west total">$125,000</td>
    </tr>

    <!-- Second row of West Region -->
    <tr>
      <td headers="west q1 jan">$47,000</td>
      <td headers="west q1 feb">$51,000</td>
      <td headers="west q1 mar">$53,000</td>
      <td headers="west total">$151,000</td>
    </tr>
  </tbody>

  <tfoot>
    <!-- Grand total row with colspan -->
    <tr>
      <th scope="row" colspan="4">Grand Total (All Regions)</th>
      <td headers="grand-total">$586,000</td>
    </tr>
  </tfoot>
</table>

The Standard

Tables with colspan and rowspan require special attention to accessibility. When cells span multiple rows or columns, you must use id and headers attributes to maintain context for screen reader users.

WCAG Criteria

  • 1.3.1 Info and Relationships: Proper header associations for spanned cells.
  • 4.1.2 Name, Role, Value: Explicit header relationships.
  • 2.4.6 Headings and Labels: Clear table structure with captions.

❌ The Bad (Inaccessible)

What’s Wrong?

  1. Missing headers attribute: Screen readers can’t determine which headers apply to spanned cells.
  2. Using <td> for headers: No semantic meaning for row headers.
  3. No scope attributes: Ambiguous header relationships.
  4. Missing caption: No context for table purpose.
  5. Colspan/rowspan without IDs: Breaks navigation for screen readers.

βœ… The Good (Accessibility-Ready Code)

Why This Works

  1. Unique IDs for All Headers: Every header cell gets a unique id.
  2. headers Attribute: Links data cells to ALL applicable headers.
  3. rowspan with Proper IDs: Row headers that span still maintain context via headers.
  4. colspan with Sub-headers: Creates hierarchical header structure.
  5. Scope Attributes: Defines direction (col/row) for each header.

Accessibility Checklist

  • Give every <th> a unique id attribute.
  • Use colspan on headers that span multiple columns.
  • Use rowspan on headers that span multiple rows.
  • Link ALL data cells to headers with headers="id1 id2 id3".
  • Include sub-headers under colspan headers with proper headers reference.
  • Use scope="col" for column headers.
  • Use scope="row" for row headers.
  • Add descriptive <caption> for table context.
πŸ“ Perfect Implementation Reference
<table>
  <caption>Sales Report</caption>

  <thead>
    <!-- Colspan header -->
    <tr>
      <th scope="col" id="region">Region</th>
      <th scope="col" id="q1" colspan="3">Q1 2024</th>
    </tr>

    <!-- Sub-headers reference the colspan -->
    <tr>
      <th scope="col" headers="region"></th>
      <th scope="col" id="jan" headers="q1">Jan</th>
      <th scope="col" id="feb" headers="q1">Feb</th>
      <th scope="col" id="mar" headers="q1">Mar</th>
    </tr>
  </thead>

  <tbody>
    <!-- Rowspan header spans 2 rows -->
    <tr>
      <th scope="row" id="east" rowspan="2">East</th>
      <td headers="east q1 jan">$45,000</td>
      <td headers="east q1 feb">$52,000</td>
      <td headers="east q1 mar">$48,000</td>
    </tr>

    <!-- Second row: cell still references east header -->
    <tr>
      <td headers="east q1 jan">$50,000</td>
      <td headers="east q1 feb">$55,000</td>
      <td headers="east q1 mar">$60,000</td>
    </tr>
  </tbody>
</table>

Technical Deep Dive

Screen Reader Announcements

  • NVDA: β€œEast Region, Q1 January, $45,000” (reads all headers correctly)
  • VoiceOver: β€œEast Region, Q1, January, $45,000” (navigates spanned cells properly)
  • JAWS: β€œEast Region row spanned 2, Q1 January, $45,000” (announces spanning)

Best Practice: Colspan and Rowspan Headers

When using colspan and rowspan, always provide unique id attributes on all header cells and reference them with the headers attribute on data cells. For colspan headers, create sub-headers that reference the parent header with headers="parent_id". For rowspan headers, ensure all rows reference the row header ID, even though the header cell visually spans multiple rows.

πŸ§ͺ

Interactive Behavioral Lab

πŸ’»

Interactive Sandbox

LIVE PREVIEW

πŸ”¬ Technical Internals

Understand how this component is processed by the browser and Assistive Technology (AT). This section bridges the gap between visual code and the hidden logic that powers accessibility.

🌲 Accessibility Tree

The data structure used by screen readers to "see" your page. It translates HTML roles and attributes into standardized objects.

βš™οΈ Event Logic

Expected behavioral standards for keyboard navigation and state transitions. Crucial for users who don't use a mouse.

  • Focus: Highlights via :focus-visible
  • Activation: Responds to Enter and Space
  • Role: Identified as Table with Colspan/Rowspan

🌐 Browser & Screen Reader Compatibility

Browser
Screen Reader
Status
🍎 Safari
VoiceOver
βœ“ Safe
πŸͺŸ Chrome
NVDA
βœ“ Safe
πŸͺŸ Edge
JAWS
βœ“ Safe
🦊 Firefox
NVDA
βœ“ Safe
πŸ“± iOS Safari
VoiceOver
βœ“ Safe
πŸ€– Chrome Android
TalkBack
βœ“ Safe