HTML Guide
A td
element’s headers
attribute must reference the ID of a th
element within the same table.
The headers
attribute is used to define explicit associations between data cells (td
) and header cells (th
) by referencing header cell IDs. For valid markup, every ID referenced in the headers
attribute must exist as a th
element’s id
within the same table. This helps users—especially those using assistive technology—understand which header(s) apply to each data cell.
For example, if a td
references headers="table_header_1"
, there must be a th id="table_header_1"
present. If it’s missing or mistyped, you’ll get the validator error you described.
Correct pattern:
<table>
<tr>
<th id="table_header_1">Header 1</th>
<th id="table_header_2">Header 2</th>
</tr>
<tr>
<td headers="table_header_1">Row 2, Column 1</td>
<td headers="table_header_2">Row 2, Column 2</td>
</tr>
</table>
Incorrect pattern (missing th
ID):
<table>
<tr>
<th>Header 1</th>
<th id="table_header_2">Header 2</th>
</tr>
<tr>
<td headers="table_header_1">Row 2, Column 1</td>
<td headers="table_header_2">Row 2, Column 2</td>
</tr>
</table>
To resolve the error, ensure every value in a td
‘s headers
attribute matches the id
of a th
element in the same table.
Learn more:
Related W3C validator issues
A <table> contains a <tr> row that has less <td> columns than the column count established by the first row. Check the table to ensure all rows have the same number of columns.
For example, in the following table, the first <tr> row defines that it’s 2 columns wide, but the second <tr> row tries to use only 1 column:
<table>
<!-- This first row sets the table as 2 columns wide -->
<tr>
<td>First</td>
<td>Second</td>
</tr>
<!-- This second row has only 1 column -->
<tr>
<td>Wrong</td>
</tr>
</table>
A <td> or <th> element has a colspan attribute value that extends beyond the total number of columns defined in the <tbody> section.
HTML tables must have rows with a consistent number of columns within each <thead>, <tbody>, or <tfoot> group. If a cell uses the colspan attribute to span more columns than exist in the current row group, the table becomes semantically incorrect and fails validation.
Example of the Issue
<table>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
<tr>
<td colspan="3">Too wide</td> <!-- Invalid: colspan="3" but only 2 columns in tbody -->
</tr>
</tbody>
</table>
How to Fix
Ensure that the maximum number of columns in any row (considering colspan) within a <tbody> does not exceed the columns defined by the longest row in that group.
Corrected Example
<table>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
<td>Cell 3</td>
</tr>
<tr>
<td colspan="3">Spans all columns</td>
</tr>
</tbody>
</table>
Or, if you only need two columns:
<table>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
<tr>
<td colspan="2">Spans two columns</td>
</tr>
</tbody>
</table>
Adjust the column count by either increasing the number of cells in each row or reducing the value of colspan as appropriate for your table structure.
Ensure each column in your table has at least one <td> or <th> cell starting in it. This error often occurs when using the colspan or rowspan attributes incorrectly.
Example of correct usage:
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td>Row 1, Cell 1</td>
<td>Row 1, Cell 2</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<td>Row 2, Cell 2</td>
</tr>
</table>
Incorrect usage example:
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td colspan="2">Row 1, Cell 1</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<!-- Missing cell in column 2 -->
</tr>
</table>
The corrected version ensuring each column has a starting cell:
<table>
<tr>
<th>Header 1</th>
<th>Header 2</th>
</tr>
<tr>
<td colspan="2">Row 1, spanning both columns</td>
</tr>
<tr>
<td>Row 2, Cell 1</td>
<td>Row 2, Cell 2</td>
</tr>
</table>
A <table> contains an incoherent number of cells on one of its columns. Check the structure of the table to find the invalid column.
Example of a valid table that defines in its header that the first column is 2 cells wide:
<table>
<thead>
<tr>
<th colspan="2">The table header</th>
</tr>
</thead>
<tbody>
<tr>
<td>The table body</td>
<td>with two columns</td>
</tr>
</tbody>
</table>
This same table with an empty body will be invalid because the table header cannot match any body columns:
<table>
<thead>
<tr>
<th colspan="2">The table header</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
A <table> contains an incoherent number of columns on one of its rows. Check the structure of the table to find the invalid row.
For example, in the following table, the first <tr> row defines that it’s 2 columns wide, but the second <tr> row tries to use 5 columns by means of a colspan attribute:
<table>
<!-- This first row sets the table as 2 columns wide -->
<tr>
<td>First</td>
<td>Second</td>
</tr>
<!-- This second row tries to use 5 columns -->
<tr>
<td colspan="5">Wrong</td>
</tr>
</table>
A td element must be placed within a tr (table row) element, not directly as a child of tbody, thead, tfoot, or table.
The td (table cell) element defines a cell of a table that contains data. According to the HTML standard, td elements must be placed inside tr elements, which are used to group table cells in a row. Directly placing a td element inside tbody, thead, tfoot, or table violates the HTML content model and will cause a validation error.
Incorrect example:
<table>
<tbody>
<td>Cell 1</td>
<td>Cell 2</td>
</tbody>
</table>
Correct example:
<table>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</tbody>
</table>
Always wrap td elements within a tr when constructing table rows.
The <th> HTML element defines a cell as a header of a group of table cells, and must appear within a <tr> element.
In the following example for a simple table, the first <tr> contains two <th> header cells naming the values for each column:
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Liza</td>
<td>49</td>
<tr>
<tr>
<td>Joe</td>
<td>47</td>
</tr>
</table>
The scope attribute must be used on a th element, not a td element.
The scope attribute helps define whether a header cell (th) refers to a column, row, or group of columns or rows in a table. According to current HTML standards, only th elements should use the scope attribute. Using scope on td elements is obsolete and invalidates your markup. To fix this, replace any td with scope with a th, and set the appropriate scope value (row, col, etc.).
Incorrect HTML Example (with validation error):
<table>
<tr>
<td scope="row">Monday</td>
<td>Meeting</td>
</tr>
</table>
Corrected HTML Example:
<table>
<tr>
<th scope="row">Monday</th>
<td>Meeting</td>
</tr>
</table>
Key points:
- Use scope="row" for row headers and scope="col" for column headers, but only on th elements.
- Never use the scope attribute on a td element.
Both <table> and <td> elements no longer accept a width attribute. Instead, you should use CSS as in this example:
<table style="width:100%;">
<tr>
<td style="width:50px;">Name</td>
</tr>
</table>
Table rows on the same <table> element must have the same number of columns, which comes determined by the first tr row.
For example, this table is wrong as the first row defines 2 columns, while the second row tries to use 4 columns:
<table>
<tr>
<td>Liza</td>
</tr>
<tr>
<td>Jimmy</td>
<td>14</td>
</tr>
</table>