Guias HTML para columnheader
Aprenda como identificar e corrigir erros comuns de validação HTML sinalizados pelo W3C Validator — para que as suas páginas cumpram os padrões e sejam renderizadas corretamente em todos os navegadores. Consulte também o nosso Guias de acessibilidade.
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:
<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:
<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:
<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:
<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.
Pronto para validar os seus sites?
Comece o seu teste gratuito hoje.