# An element with “role=columnheader” must be contained in, or owned by, an element with “role=row”.

> Canonical HTML version: https://rocketvalidator.com/html-validation/an-element-with-role-columnheader-must-be-contained-in-or-owned-by-an-element-with-role-row
> Attribution: Rocket Validator (https://rocketvalidator.com)
> License: CC BY 4.0 (https://creativecommons.org/licenses/by/4.0/)

The ARIA specification defines a strict ownership hierarchy for table-related roles. A `columnheader` represents a header cell for a column, analogous to a `<th>` element in native HTML. For assistive technologies like screen readers to correctly announce column headers and associate them with the data cells beneath them, the `columnheader` must exist within a `row` context. The required structure is:

- An element with `role="table"`, `role="grid"`, or `role="treegrid"` serves as the container.
- Inside it, elements with `role="rowgroup"` (optional) or `role="row"` organize the rows.
- Each `role="row"` element contains one or more elements with `role="columnheader"`, `role="rowheader"`, or `role="cell"`.

When a `role="columnheader"` element is placed directly inside a `role="table"` or `role="grid"` container — or any other element that is not `role="row"` — the validator raises this error. Without the `row` wrapper, screen readers cannot navigate the table structure properly. Users who rely on assistive technology may hear disjointed content or miss the column headers entirely, making the data table unusable.

The best practice, whenever feasible, is to use native HTML table elements (`<table>`, `<thead>`, `<tr>`, `<th>`, `<td>`). These carry implicit ARIA roles and establish the correct ownership relationships automatically, eliminating this entire category of errors. Only use ARIA table roles when you genuinely cannot use native table markup — for example, when building a custom grid widget with non-table elements for layout reasons.

## Examples

### Incorrect: `columnheader` not inside a `row`

In this example, the `columnheader` elements are direct children of the `table` container, with no `role="row"` wrapper:

```html
<div role="table" aria-label="Employees">
  <div role="columnheader">Name</div>
  <div role="columnheader">Department</div>
  <div role="row">
    <div role="cell">Alice</div>
    <div role="cell">Engineering</div>
  </div>
</div>
```

### Correct: `columnheader` inside a `row`

Wrapping the column headers in an element with `role="row"` fixes the issue:

```html
<div role="table" aria-label="Employees">
  <div role="row">
    <div role="columnheader">Name</div>
    <div role="columnheader">Department</div>
  </div>
  <div role="row">
    <div role="cell">Alice</div>
    <div role="cell">Engineering</div>
  </div>
</div>
```

### Correct: Using `rowgroup` for additional structure

You can optionally use `role="rowgroup"` to separate headers from body rows, similar to `<thead>` and `<tbody>`. The `columnheader` elements must still be inside a `row`:

```html
<div role="table" aria-label="Employees">
  <div role="rowgroup">
    <div role="row">
      <div role="columnheader">Name</div>
      <div role="columnheader">Department</div>
    </div>
  </div>
  <div role="rowgroup">
    <div role="row">
      <div role="cell">Alice</div>
      <div role="cell">Engineering</div>
    </div>
  </div>
</div>
```

### Best practice: Use native table elements

Native HTML tables have built-in semantics that make ARIA roles unnecessary. A `<th>` inside a `<tr>` already behaves as a `columnheader` inside a `row`:

```html
<table>
  <thead>
    <tr>
      <th>Name</th>
      <th>Department</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <td>Alice</td>
      <td>Engineering</td>
    </tr>
  </tbody>
</table>
```

This approach is simpler, more robust across browsers and assistive technologies, and avoids the risk of ARIA misuse. Reserve ARIA table roles for situations where native table markup is not an option.
