# The “role” attribute must not be used on a “th” element which has a “table” ancestor with no “role” attribute, or with a “role” attribute whose value is “table”, “grid”, or “treegrid”.

> Canonical HTML version: https://rocketvalidator.com/html-validation/the-role-attribute-must-not-be-used-on-a-th-element-which-has-a-table-ancestor-with-no-role-attribute-or-with-a-role-attribute-whose-value-is-table-grid-or-treegrid
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

A `<th>` gets its ARIA role from the table it belongs to, so it can't have a `role` attribute when that `<table>` has no `role`, or has `role="table"`, `role="grid"` or `role="treegrid"`.

In those tables the browser works out what each header cell is. A `<th>` inside `<thead>`, or in a row of headers above the data, is exposed as `columnheader`. A `<th>` at the start of a data row is exposed as `rowheader`. When the layout is ambiguous, `scope="col"` or `scope="row"` states the direction. Screen readers use these roles to announce the right header as the user moves from one data cell to the next.

The ARIA in HTML specification allows no `role` value at all on a `<th>` in these tables, so the validator reports this error whatever the value is. With `role="columnheader"` or `role="rowheader"` you also get a warning that the role is unnecessary for the element, and deleting the attribute clears both messages. Any other value replaces the header role. A sortable header marked `role="button"`, or a header marked `role="presentation"`, stops being a header, and screen readers no longer read its text before the cells it labels.

To make a column sortable, keep the `<th>` as it is, put a `<button>` inside it, and set `aria-sort` on the `<th>` for the column that is currently sorted. If the table exists only for layout, put `role="presentation"` on the `<table>` instead. A table with a role other than `table`, `grid` or `treegrid` loses its table semantics, and this rule no longer applies to its cells.

Table plugins and page builders often add a role to every part of a table: `role="table"` on the `<table>`, `role="rowgroup"` on `<thead>` and `<tbody>`, `role="row"` on each `<tr>` and `role="cell"` on each `<td>`. The validator reports all of them, with errors for the roles on `<tr>` and `<td>` and warnings for the rest, so remove them in the same change.

## Invalid example

```html
<table>
  <thead>
    <tr>
      <th scope="col" role="columnheader">Product</th>
      <th scope="col" role="button" tabindex="0">Price</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row" role="rowheader">Desk lamp</th>
      <td>$45</td>
    </tr>
    <tr>
      <th scope="row" role="rowheader">Notebook</th>
      <td>$8</td>
    </tr>
  </tbody>
</table>
```

## Valid example

```html
<table>
  <thead>
    <tr>
      <th scope="col">Product</th>
      <th scope="col" aria-sort="descending">
        <button type="button">Price</button>
      </th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">Desk lamp</th>
      <td>$45</td>
    </tr>
    <tr>
      <th scope="row">Notebook</th>
      <td>$8</td>
    </tr>
  </tbody>
</table>
```
