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

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

Every element with `role="cell"` needs an ancestor with `role="row"`, or a row that claims it through `aria-owns`.

An ARIA table nests its roles in a fixed order: `table`, then an optional `rowgroup`, then `row`, then `cell` (or `columnheader` and `rowheader`). Screen readers use that structure to announce a cell's row and column and to let people jump from cell to cell. A cell with no row above it has no position in the table, so a screen reader may read it as loose text or skip it during table navigation.

This usually happens when a table built from `<div>` elements has a wrapper for each row that carries a class for styling but never gets `role="row"`. If that wrapper sits inside a `role="rowgroup"`, the validator also reports that a child of the rowgroup must have `role="row"`. Adding the missing role to the wrapper fixes both messages.

The row doesn't have to be the cell's direct parent. The validator accepts plain `<div>` or `<span>` wrappers between a `role="row"` element and its cells, so you can keep layout wrappers as long as some ancestor has the row role. When the cells can't sit inside the row in the DOM, give each cell an `id` and list those ids in `aria-owns` on the row.

Older validator versions word this message as `an element with “role=row”` instead of `an element with the “role” value “row”`, with the same cause and fix.

If the data is really tabular, a native `<table>` with `<tr>` and `<td>` gives you this structure without any `role` attributes.

## Invalid example

Each plan wrapper groups two cells, but nothing marks it as a row.

```html
<div role="table" aria-label="Subscription plans">
  <div role="rowgroup">
    <div class="plan">
      <div role="cell">Basic</div>
      <div role="cell">$10 per month</div>
    </div>
    <div class="plan">
      <div role="cell">Pro</div>
      <div role="cell">$25 per month</div>
    </div>
  </div>
</div>
```

## Valid example

With `role="row"` on each wrapper, every cell has a row to belong to.

```html
<div role="table" aria-label="Subscription plans">
  <div role="rowgroup">
    <div role="row" class="plan">
      <div role="cell">Basic</div>
      <div role="cell">$10 per month</div>
    </div>
    <div role="row" class="plan">
      <div role="cell">Pro</div>
      <div role="cell">$25 per month</div>
    </div>
  </div>
</div>
```
