Skip to main content
HTML Validation

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

About This HTML Issue

The ARIA specification defines a strict ownership hierarchy for table-related roles. A role="cell" element must be “owned by” an element with role="row", meaning it must either be a direct child of that element or be associated with it via the aria-owns attribute. This mirrors how native HTML tables work: a <td> element must live inside a <tr> element. When you use ARIA roles to build custom table structures from non-table elements like <div> or <span>, you are responsible for maintaining this same hierarchy manually.

The expected nesting order for an ARIA table is:

  1. role="table" — the outermost container
  2. role="rowgroup" (optional) — groups rows together, like <thead>, <tbody>, or <tfoot>
  3. role="row" — a single row of cells
  4. role="cell" or role="columnheader" / role="rowheader" — individual cells

When a role="cell" element is placed directly inside a role="table" or any other container that isn’t role="row", screen readers lose the ability to announce row and column positions. Users who rely on table navigation shortcuts (such as moving between cells with arrow keys) will find the table unusable. This is not just a validation concern — it directly impacts whether people can access your content.

This issue commonly arises when developers add intermediate wrapper elements for styling purposes and accidentally break the required parent-child relationship, or when they forget to assign role="row" to a container element.

How to Fix

Ensure every element with role="cell" is a direct child of an element with role="row". If you have wrapper elements between the row and cell for layout or styling, either remove them, move the role assignments, or use aria-owns on the row element to explicitly claim ownership of the cells.

Examples

Incorrect — Cell Without a Row Parent

This triggers the validation error because role="cell" elements are direct children of the role="table" container, with no role="row" in between.

<div role="table">
  <div role="cell">Name</div>
  <div role="cell">Email</div>
</div>

Incorrect — Intermediate Wrapper Breaking Ownership

Here, a styling wrapper sits between the row and its cells. Since the <div> without a role is not a role="row", the cells are not properly owned.

<div role="table">
  <div role="row">
    <div class="cell-wrapper">
      <div role="cell">Row 1, Cell 1</div>
      <div role="cell">Row 1, Cell 2</div>
    </div>
  </div>
</div>

Correct — Cells Directly Inside Rows

Each role="cell" is a direct child of a role="row" element, forming a valid ARIA table structure.

<div role="table" aria-label="Team members">
  <div role="row">
    <div role="columnheader">Name</div>
    <div role="columnheader">Email</div>
  </div>
  <div role="row">
    <div role="cell">Alice</div>
    <div role="cell">alice@example.com</div>
  </div>
  <div role="row">
    <div role="cell">Bob</div>
    <div role="cell">bob@example.com</div>
  </div>
</div>

Correct — Using Rowgroups

You can optionally group rows with role="rowgroup", similar to <thead> and <tbody>. The cells still must be direct children of their rows.

<div role="table" aria-label="Quarterly results">
  <div role="rowgroup">
    <div role="row">
      <div role="columnheader">Quarter</div>
      <div role="columnheader">Revenue</div>
    </div>
  </div>
  <div role="rowgroup">
    <div role="row">
      <div role="cell">Q1</div>
      <div role="cell">$10,000</div>
    </div>
    <div role="row">
      <div role="cell">Q2</div>
      <div role="cell">$12,500</div>
    </div>
  </div>
</div>

Correct — Using Native HTML Instead

If your content is genuinely tabular data, consider using native HTML table elements instead of ARIA roles. Native tables have built-in semantics and require no additional role attributes.

<table>
  <tr>
    <th>Name</th>
    <th>Email</th>
  </tr>
  <tr>
    <td>Alice</td>
    <td>alice@example.com</td>
  </tr>
</table>

Native HTML tables are always preferable when they suit your use case. The first rule of ARIA is: if you can use a native HTML element that already has the semantics you need, use it instead of adding ARIA roles to a generic element.

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?

Ready to validate your sites?
Start your free trial today.