# Data Tables

Table structure, headers, captions, complex tables.

## Criteria

| Standard | Criteria                                          |
| -------- | ------------------------------------------------- |
| WCAG 2.2 | 1.3.1 Info and Relationships (A) — tables portion |
| WCAG 2.2 | 1.3.2 Meaningful Sequence (A) — layout tables     |
| WCAG 2.2 | 4.1.2 Name, Role, Value (A) — layout tables       |
| RGAA 4.1 | 5.1–5.8 Tableaux                                  |

### Info and Relationships (tables) — WCAG 1.3.1 (A) / RGAA 5.1–5.8

Data tables must have properly declared headers (`<th>` with `scope`), captions (`<caption>`), and correct cell-to-header associations. Complex tables use `id` + `headers` attributes. Layout tables must use `role="presentation"` and must not contain `<th>`, `<thead>`, `<tfoot>`, `scope`, or `headers`.

---

## RGAA 5.1 — Complex data table summary (A)

**Criterion:** Each complex data table must have a summary describing its nature and structure.

WCAG: 1.3.1 (A) — Techniques: H73

### Test 5.1.1

Does each complex data table have a summary available?

**Methodology:**

1. Find complex data tables in the document (`<table>` or element with `role="table"` containing headers not distributed solely on the first row and/or first column, or whose scope does not cover the entire column or row).
2. For each complex data table, verify that a text passage explaining the nature and structure of the table is present via:
   - A `<caption>` element; or
   - A `summary` attribute on `<table>` (HTML versions prior to HTML5); or
   - A text passage linked via `aria-describedby`.
3. If true for every complex data table, **the test is validated**.

### Notes techniques

The HTML spec proposes several methods to link a summary to a table (`aria-describedby`, `<figure>` with `<figcaption>` or `<p>`, `<details>` inside `<caption>`). These methods do not yet have sufficient support for current use.

---

## RGAA 5.2 — Complex data table summary relevance (A)

**Criterion:** For each complex data table that has a summary, the summary must be relevant.

WCAG: 1.3.1 (A) — Techniques: H73

### Test 5.2.1

For each complex data table that has a summary, is the summary relevant?

**Methodology:**

1. Find summaries of complex data tables (as determined by test 5.1.1).
2. For each summary, verify that its content is relevant (accurately describes the nature and structure of the table).
3. If true for every complex data table summary, **the test is validated**.

---

## RGAA 5.3 — Layout table linearization (A)

**Criterion:** For each layout table, the linearized content must remain comprehensible and the table must use `role="presentation"`.

WCAG: 1.3.2 (A), 4.1.2 (A) — Techniques: F49, ARIA4

### Test 5.3.1

Does each layout table satisfy these conditions?

- The linearized content remains comprehensible.
- The `<table>` element has `role="presentation"`.

**Methodology:**

1. Find layout tables in the document.
2. For each layout table, verify that:
   - The cell access order is coherent with the content;
   - The `<table>` element has a WAI-ARIA `role="presentation"` attribute.
3. If true for every layout table, **the test is validated**.

---

## RGAA 5.4 — Data table title association (A)

**Criterion:** For each data table that has a title, the title must be correctly associated with the table.

WCAG: 1.3.1 (A) — Techniques: H39

### Test 5.4.1

For each data table with a title, is the title correctly associated?

**Methodology:**

1. Find data tables with a title in the document.
2. For each title, verify it is provided via:
   - A `<caption>` element; or
   - A `title` attribute; or
   - An `aria-label` attribute; or
   - An `aria-labelledby` attribute referencing a text passage.
3. If true for every data table title, **the test is validated**.

---

## RGAA 5.5 — Data table title relevance (A)

**Criterion:** For each data table that has a title, the title must be relevant.

WCAG: 1.3.1 (A) — Techniques: H39

### Test 5.5.1

For each data table with a title, does the title clearly and concisely identify the table's content?

**Methodology:**

1. Find data tables with a title in the document.
2. For each title, verify it is relevant (clearly and concisely describes the table content).
3. If true for every data table title, **the test is validated**.

---

## RGAA 5.6 — Column and row header declaration (A)

**Criterion:** For each data table, every column header and row header must be correctly declared.

WCAG: 1.3.1 (A) — Techniques: H51, F91

### Test 5.6.1

For each data table, does each column header applying to the entire column satisfy one of these conditions?

- The column header is structured with a `<th>` element.
- The column header is structured with an element having `role="columnheader"`.

**Methodology:**

1. Find data tables in the document.
2. For each column header applying to the entire column, verify it is structured via:
   - A `<th>` element; or
   - An element with `role="columnheader"`.
3. If true for every full-column header, **the test is validated**.

### Test 5.6.2

For each data table, does each row header applying to the entire row satisfy one of these conditions?

- The row header is structured with a `<th>` element.
- The row header is structured with an element having `role="rowheader"`.

**Methodology:**

1. Find data tables in the document.
2. For each row header applying to the entire row, verify it is structured via:
   - A `<th>` element; or
   - An element with `role="rowheader"`.
3. If true for every full-row header, **the test is validated**.

### Test 5.6.3

For each data table, is each header that does NOT apply to the entire row or column structured with a `<th>` element?

**Methodology:**

1. Find data tables in the document.
2. For each header not applying to the entire row or column, verify it is structured with a `<th>` element.
3. If true for every partial-scope header, **the test is validated**.

### Test 5.6.4

For each data table, is each cell associated with multiple headers structured with a `<td>` or `<th>` element?

**Methodology:**

1. Find data tables in the document.
2. For each cell associated with multiple headers, verify it is structured with a `<th>` or `<td>` element.
3. If true for every multi-header cell, **the test is validated**.

---

## RGAA 5.7 — Header-to-cell association technique (A)

**Criterion:** For each data table, the appropriate technique to associate each cell with its headers must be used.

WCAG: 1.3.1 (A) — Techniques: H43, H63, F90

### Test 5.7.1

For each `<th>` whose content applies to the entire row or column, does the `<th>` satisfy one of these conditions?

- The `<th>` has a unique `id` attribute.
- The `<th>` has a `scope` attribute.
- The `<th>` has `role="rowheader"` or `role="columnheader"`.

**Methodology:**

1. Find data tables in the document.
2. For each `<th>` applying to the entire row or column, verify it has:
   - A unique `id` attribute; or
   - A `scope` attribute; or
   - A WAI-ARIA `role="rowheader"` or `role="columnheader"`.
3. If true for every full-scope `<th>`, **the test is validated**.

### Test 5.7.2

For each `<th>` applying to the entire row or column and having a `scope` attribute, does the `<th>` satisfy one of these conditions?

- `scope="row"` for row headers.
- `scope="col"` for column headers.

**Methodology:**

1. Find data tables in the document.
2. For each `<th>` applying to the entire row or column and having `scope`, verify:
   - `scope="row"` for row headers; or
   - `scope="col"` for column headers.
3. If true for every scoped full-row/column `<th>`, **the test is validated**.

### Test 5.7.3

For each `<th>` whose content does NOT apply to the entire row or column, does it satisfy these conditions?

- No `scope` attribute.
- No `role="rowheader"` or `role="columnheader"`.
- Has a unique `id` attribute.

**Methodology:**

1. Find data tables in the document.
2. For each `<th>` not applying to the entire row or column, verify:
   - It has a unique `id` attribute; AND
   - It does NOT have a `scope` attribute; AND
   - It does NOT have `role="rowheader"` or `role="columnheader"`.
3. If true for every partial-scope `<th>`, **the test is validated**.

### Test 5.7.4

For each `<td>` or `<th>` associated with one or more headers that have an `id` attribute, does the element satisfy these conditions?

- It has a `headers` attribute.
- The `headers` attribute lists the `id` values of all associated headers.

**Methodology:**

1. Find data tables in the document.
2. For each `<td>` or `<th>` associated with headers that have `id`, verify:
   - The element has a `headers` attribute; AND
   - The `headers` value lists all associated header `id` values.
3. If true for every cell associated with id-bearing headers, **the test is validated**.

### Test 5.7.5

For each element with `role="rowheader"` or `role="columnheader"` whose content applies to the entire row or column, does it satisfy one of these conditions?

- `role="rowheader"` for row headers.
- `role="columnheader"` for column headers.

**Methodology:**

1. Find data tables in the document.
2. For each element with `role="rowheader"` or `role="columnheader"` applying to the entire row or column, verify:
   - `role="rowheader"` for row headers; or
   - `role="columnheader"` for column headers.
3. If true for every ARIA-roled full-scope header, **the test is validated**.

### Cas particuliers

For data tables with headers on a single row or single column only, headers may be structured with `<th>` elements without a `scope` attribute.

### Notes techniques

If the `headers` attribute is implemented on a cell already linked to a header via `scope` (`col` or `row`), assistive technologies will use the headers referenced by `headers` and ignore those linked via `scope`.

---

## RGAA 5.8 — Layout table must not use data table elements (A)

**Criterion:** Each layout table must not use elements specific to data tables.

WCAG: 1.3.1 (A) — Techniques: F46

### Test 5.8.1

Does each layout table (`<table>`) satisfy these conditions?

- No `summary` attribute (or empty), no `<caption>`, `<th>`, `<thead>`, `<tfoot>` child elements, no elements with `role="rowheader"` or `role="columnheader"`.
- `<td>` cells do not have `scope`, `headers`, or `axis` attributes.

**Methodology:**

1. Find layout tables in the document.
2. For each layout table, verify that:
   - The `<table>` has no `summary` attribute, no `<caption>`, `<thead>`, `<th>`, `<tfoot>` children, no elements with `role="rowheader"` or `role="columnheader"`;
   - `<td>` elements have no `scope`, `headers`, or `axis` attributes.
3. If true for every layout table, **the test is validated**.

---

## Patterns

**Simple data table:**

```html
<table>
  <caption>Product pricing by region</caption>
  <thead>
    <tr>
      <th scope="col">Region</th>
      <th scope="col">Price</th>
      <th scope="col">Availability</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Europe</th>
      <td>€100</td>
      <td>In stock</td>
    </tr>
  </tbody>
</table>
```

**Complex table with multi-level headers:**

```html
<table>
  <caption>Quarterly sales by product and region</caption>
  <thead>
    <tr>
      <td></td>
      <th id="q1" scope="col">Q1</th>
      <th id="q2" scope="col">Q2</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th id="shoes" scope="row">Shoes</th>
      <td headers="q1 shoes">150</td>
      <td headers="q2 shoes">200</td>
    </tr>
  </tbody>
</table>
```

**Layout table (when unavoidable):**

```html
<table role="presentation">
  <tr>
    <td>Content</td>
    <td>Content</td>
  </tr>
</table>
```

**Shopify** — dynamic table from metafields:

```liquid
<table>
  <caption>{{ section.settings.table_title }}</caption>
  <thead>
    <tr>
      {%- for header in section.settings.headers -%}
        <th scope="col">{{ header }}</th>
      {%- endfor -%}
    </tr>
  </thead>
  <tbody>
    {%- for row in section.settings.rows -%}
      <tr>
        <th scope="row">{{ row.label }}</th>
        {%- for cell in row.cells -%}
          <td>{{ cell }}</td>
        {%- endfor -%}
      </tr>
    {%- endfor -%}
  </tbody>
</table>
```
