HTML Guides for rowspan
Learn how to identify and fix common HTML validation errors flagged by the W3C Validator — so your pages are standards-compliant and render correctly across every browser. Also check our Accessibility Guides.
The rowspan attribute on a <td> must hold a whole number from 0 to 65534, so leaving it empty is an error.
A bare rowspan with no value counts as empty and gets the same message. A value made of spaces, or a negative number like -1, gets a different error that starts with "Expected a digit".
Empty rowspan attributes often come from table plugins and page builders that write both span attributes on every cell and leave them blank when no cells were merged. Check the same cells for colspan="", which the validator reports in its own message ending in "not a valid positive integer".
Browsers read an empty rowspan as 1, the same as no attribute, so deleting it leaves the table unchanged. Don't reach for rowspan="0" as a replacement: it is valid, unlike colspan="0", but it stretches the cell down through every remaining row of its <thead>, <tbody> or <tfoot>. Write the attribute only on cells that cover two or more rows.
Invalid example
<table>
<tr>
<th>Day</th>
<th>Time</th>
<th>Session</th>
</tr>
<tr>
<td rowspan="2">Monday</td>
<td rowspan="">9:00</td>
<td rowspan="">Welcome</td>
</tr>
<tr>
<td>11:00</td>
<td>Workshop</td>
</tr>
</table>
Valid example
<table>
<tr>
<th>Day</th>
<th>Time</th>
<th>Session</th>
</tr>
<tr>
<td rowspan="2">Monday</td>
<td>9:00</td>
<td>Welcome</td>
</tr>
<tr>
<td>11:00</td>
<td>Workshop</td>
</tr>
</table>
A rowspan on a <th> sets how many rows the header cell covers, and it only accepts a whole number from 0 to 65534, so rowspan="" fails validation.
The validator reports a bare rowspan, written with no value, in exactly the same way. A value that holds only spaces, or a negative number such as -1, produces another message instead, one that begins with "Expected a digit".
The usual source is a header row generated by a table plugin or theme that prints rowspan and colspan on every <th> and leaves them blank when the cells aren't merged. Look at those headers for colspan="" as well. The validator flags it in a separate message, "not a valid positive integer", because colspan has to be at least 1.
An empty rowspan makes no visual difference: browsers read it as 1, the same value they use when the attribute is absent, so you can delete it safely. Avoid swapping in rowspan="0". That value passes validation, but it makes the header reach down to the last row of its <thead>, <tbody> or <tfoot>. Leave rowspan only on headers that span two or more rows, such as a row header that labels a group of rows.
Invalid example
<table>
<tr>
<th rowspan="">Region</th>
<th rowspan="">Store</th>
<th rowspan="">Sales</th>
</tr>
<tr>
<th rowspan="2">North</th>
<td>Leeds</td>
<td>1,200</td>
</tr>
<tr>
<td>York</td>
<td>950</td>
</tr>
</table>
Valid example
<table>
<tr>
<th>Region</th>
<th>Store</th>
<th>Sales</th>
</tr>
<tr>
<th rowspan="2">North</th>
<td>Leeds</td>
<td>1,200</td>
</tr>
<tr>
<td>York</td>
<td>950</td>
</tr>
</table>
A cell inside a <thead> has a rowspan value larger than the number of rows left in that <thead>.
The <thead>, <tbody> and <tfoot> elements each form a row group, and a cell's rowspan can't reach from one row group into the next. When a header cell asks for more rows than its <thead> holds, the browser stops the cell at the last header row, as if the extra part of the rowspan weren't there.
This usually comes from a two-level header. The first row has a cell such as "Name" with rowspan="2" next to a grouped heading with colspan="2", and the row of sub-headings that belongs under the group ends up after </thead>, as the first row of the <tbody>. The "Name" cell can't extend into the <tbody>, so that row ends up one cell short, and the validator usually adds a second message about it: "A table row was 2 columns wide, which is less than the column count established by the first row (3)."
Put every header row inside the <thead> so the span has rows to cover. If the header really has a single row, remove the rowspan.
Invalid example
<table>
<thead>
<tr>
<th rowspan="2">Name</th>
<th colspan="2">Score</th>
</tr>
</thead>
<tbody>
<tr>
<th>Round 1</th>
<th>Round 2</th>
</tr>
<tr>
<td>Ana</td>
<td>8</td>
<td>9</td>
</tr>
</tbody>
</table>
Valid example
<table>
<thead>
<tr>
<th rowspan="2">Name</th>
<th colspan="2">Score</th>
</tr>
<tr>
<th>Round 1</th>
<th>Round 2</th>
</tr>
</thead>
<tbody>
<tr>
<td>Ana</td>
<td>8</td>
<td>9</td>
</tr>
</tbody>
</table>
Validate at scale.
Ship accessible websites, faster.
Automated HTML & accessibility validation for large sites. Check thousands of pages against WCAG guidelines and W3C standards in minutes, not days.
1K Weekly
1,000 monthly checks. Cancel anytime.
Get 1K Weekly →Join teams across 40+ countries