HTML Guides for columns
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.
In HTML, the structure of a <table> is implicitly defined by its rows and columns. The first <tr> in a table (or table section like <thead>, <tbody>, or <tfoot>) establishes the expected column count for the entire table. When a subsequent row contains more cells than the first row, the validator raises this error because the table's column grid becomes inconsistent.
Browsers will still attempt to render mismatched tables, but the results can be unpredictable and problematic. Screen readers and other assistive technologies rely on a well-formed table grid to correctly associate data cells with their headers. An inconsistent column count can cause these tools to misread or skip content, making the table inaccessible to users who depend on them. Additionally, inconsistent tables are harder to style with CSS and can lead to unexpected layout shifts.
There are several common causes for this issue:
- Missing cells in the first row — The first row has fewer
<td>or<th>elements than subsequent rows. - Forgotten
colspan— A cell in the first row should span multiple columns but is missing acolspanattribute. - Extra cells in later rows — A row further down the table has more cells than intended.
- Mismatched
colspanarithmetic — The sum of cells and theircolspanvalues doesn't add up consistently across rows.
To fix this, review every row in the table and ensure the total column count (accounting for colspan and rowspan attributes) is the same for each row.
Examples
Incorrect: second row has more columns than the first
The first row defines 1 column, but the second row has 2 columns.
<table>
<tr>
<td>Liza</td>
</tr>
<tr>
<td>Jimmy</td>
<td>14</td>
</tr>
</table>
Fixed: add missing cells to the first row
Make both rows have 2 columns by adding a header or data cell to the first row.
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Jimmy</td>
<td>14</td>
</tr>
</table>
Fixed: use colspan if the first row intentionally spans the full width
If the first row is meant to be a single spanning header, use colspan to match the total column count.
<table>
<tr>
<th colspan="2">Student Info</th>
</tr>
<tr>
<td>Jimmy</td>
<td>14</td>
</tr>
</table>
Incorrect: later row exceeds column count with extra cells
<table>
<tr>
<th>Name</th>
<th>Age</th>
</tr>
<tr>
<td>Liza</td>
<td>12</td>
<td>Extra cell</td>
</tr>
</table>
Fixed: remove the extra cell or expand the header row
<table>
<tr>
<th>Name</th>
<th>Age</th>
<th>Notes</th>
</tr>
<tr>
<td>Liza</td>
<td>12</td>
<td>Extra cell</td>
</tr>
</table>
Incorrect: colspan mismatch causes inconsistent totals
The first row spans 3 columns total (1 + colspan="2"), but the second row has 4 cells.
<table>
<tr>
<th>Name</th>
<th colspan="2">Contact</th>
</tr>
<tr>
<td>Liza</td>
<td>liza@example.com</td>
<td>555-0100</td>
<td>Room 4</td>
</tr>
</table>
Fixed: adjust colspan or cell count so all rows match
<table>
<tr>
<th>Name</th>
<th colspan="3">Contact & Location</th>
</tr>
<tr>
<td>Liza</td>
<td>liza@example.com</td>
<td>555-0100</td>
<td>Room 4</td>
</tr>
</table>
When debugging this issue, count the effective columns for each row by adding up the number of cells plus any additional columns contributed by colspan values (a colspan="3" cell counts as 3 columns). Every row in the table must produce the same total.
A row in this table has more cells than its <colgroup> and <col> elements declare, so some of its cells sit past the last column the markup defines.
When a table has column markup, that markup sets the column count before any row is read. Each <col> adds one column, or as many as its span attribute says. A <colgroup> with no <col> inside adds the number in its own span, which defaults to 1. A row is X columns wide when its cells add up to X, with each cell counting as many columns as its colspan. The validator reports this error once for every row wider than the Y columns the markup declares.
A common cause is an empty <colgroup></colgroup> that a table editor or template writes into every table. It still counts as one column, so every row of a table with two or more columns triggers the error. Another cause is a column added to the rows but not to the <colgroup>. Browsers still show the extra cells, but styles set on <col>, such as width or background-color, don't reach the columns the markup leaves out.
To fix it, declare every column the rows use: add the missing <col> elements, raise the span, or remove a <colgroup> that doesn't style anything.
Invalid example
The <colgroup> declares one column, but each row has two cells:
<table>
<colgroup>
<col class="item">
</colgroup>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
<tr>
<td>Coffee</td>
<td>2.50</td>
</tr>
</table>
Valid example
One <col> for each column in the rows:
<table>
<colgroup>
<col class="item">
<col class="price">
</colgroup>
<tr>
<th>Item</th>
<th>Price</th>
</tr>
<tr>
<td>Coffee</td>
<td>2.50</td>
</tr>
</table>
HTML tables establish their column count based on the first row. When subsequent rows have fewer <td> or <th> cells than that initial row defines, the table structure becomes invalid. Browsers will typically render these tables by leaving blank space where the missing cells should be, but the underlying markup is malformed.
This matters for several important reasons. Screen readers and other assistive technologies rely on a consistent table structure to navigate cells and associate data with the correct headers. When cells are missing, users who depend on these tools may receive confusing or incorrect information. Additionally, inconsistent row widths can lead to unpredictable layout behavior across different browsers and make your table markup harder to maintain.
When counting columns, remember that the colspan attribute contributes to the total. A single <td colspan="3"> counts as three columns, not one. So if your first row has two <td> elements and one of them has colspan="2", the table is three columns wide, and every other row must also account for three columns.
How to Fix
There are several approaches depending on your intent:
- Add the missing cells — If data was accidentally omitted, add the appropriate
<td>or<th>elements to complete the row. - Use
colspan— If a cell should intentionally span multiple columns, use thecolspanattribute so the total column count matches. - Add empty cells — If a cell simply has no content, include an empty
<td></td>to maintain the structure.
Examples
❌ Row with fewer columns than the first row
The first row establishes a 3-column table, but the second row only has 2 cells:
<table>
<tr>
<td>Name</td>
<td>Role</td>
<td>Department</td>
</tr>
<tr>
<td>Alice</td>
<td>Engineer</td>
</tr>
</table>
✅ Fix by adding the missing cell
<table>
<tr>
<td>Name</td>
<td>Role</td>
<td>Department</td>
</tr>
<tr>
<td>Alice</td>
<td>Engineer</td>
<td>Product</td>
</tr>
</table>
✅ Fix by using colspan to span remaining columns
If the second row intentionally has fewer logical cells, use colspan so the total still matches:
<table>
<tr>
<td>Name</td>
<td>Role</td>
<td>Department</td>
</tr>
<tr>
<td>Alice</td>
<td colspan="2">Engineer — General</td>
</tr>
</table>
✅ Fix by adding an empty cell
If there's simply no data for that column, include an empty cell:
<table>
<tr>
<td>Name</td>
<td>Role</td>
<td>Department</td>
</tr>
<tr>
<td>Alice</td>
<td>Engineer</td>
<td></td>
</tr>
</table>
❌ Mismatch caused by colspan in the first row
Be careful when the first row uses colspan, as it increases the effective column count:
<table>
<tr>
<td colspan="2">Full Name</td>
<td>Role</td>
</tr>
<tr>
<td>Alice</td>
<td>Engineer</td>
</tr>
</table>
Here the first row spans 3 columns (2 + 1), but the second row only has 2 cells.
✅ Fix by matching the full column count
<table>
<tr>
<td colspan="2">Full Name</td>
<td>Role</td>
</tr>
<tr>
<td>Alice</td>
<td>Smith</td>
<td>Engineer</td>
</tr>
</table>
A row in this table has fewer cells than its <colgroup> and <col> elements declare, so the row ends before the last column the markup defines.
Column markup sets the column count before any row is read. Each <col> adds one column, or as many as its span attribute says, and a <colgroup> with no <col> inside adds the number in its own span. A row is X columns wide when its cells add up to X, counting each cell's colspan and any cell from a row above that reaches down with rowspan. The validator reports this error once for every row narrower than the Y columns the markup declares. When no row reaches column Y at all, it also reports that table column Y established by element col (or colgroup) has no cells beginning in it.
A common cause is a column deleted from the rows while its <col> stays in the <colgroup>, for example after removing a column in a visual table editor. Without column markup, a short row only gets a warning. With it, the validator reports an error.
To fix it, make the column markup and the rows agree. If the column is gone, remove its <col> or lower the span. If the column should stay, add the missing cells to each short row, with an empty <td></td> where there is no data. A colspan on the last cell of a short row also clears this error, but when no row has a cell that starts in the last column, the validator then reports that column as having no cells.
Invalid example
The <colgroup> declares four columns, but each row has three cells:
<table>
<colgroup>
<col class="item">
<col class="size">
<col class="price">
<col class="stock">
</colgroup>
<tr>
<th>Item</th>
<th>Size</th>
<th>Price</th>
</tr>
<tr>
<td>T-shirt</td>
<td>M</td>
<td>15.00</td>
</tr>
</table>
Valid example
The <col> for the removed column is gone, so the markup declares three columns:
<table>
<colgroup>
<col class="item">
<col class="size">
<col class="price">
</colgroup>
<tr>
<th>Item</th>
<th>Size</th>
<th>Price</th>
</tr>
<tr>
<td>T-shirt</td>
<td>M</td>
<td>15.00</td>
</tr>
</table>
This table's <col> elements declare more columns than its rows fill, so column N has no <td> or <th> starting in it.
Each <col> inside a <colgroup> adds one column to the table, or as many columns as its span attribute says. The HTML table model then requires every column to have at least one cell that begins in it. A cell that only reaches the column through colspan doesn't count: with <col span="3"> and a row of <td>Alice</td><td colspan="2">2019</td>, column 3 is still reported.
The usual cause is column markup that no longer matches the content, such as a template that always writes the same <colgroup>, or a column removed from every row but left in the <colgroup>. Rows shorter than the column markup also trigger a companion error, "A table row was 2 columns wide, which is less than the column count established using column markup (3)".
To fix it, make the column markup match the rows. Remove the extra <col> elements or lower their span, or add the missing cells if that column should hold data.
Invalid example
Three <col> elements, but every row has only two cells:
<table>
<colgroup>
<col class="name">
<col class="role">
<col class="year">
</colgroup>
<tr>
<th>Name</th>
<th>Year</th>
</tr>
<tr>
<td>Alice Moreno</td>
<td>2019</td>
</tr>
</table>
Valid example
The <colgroup> declares the same two columns the rows use:
<table>
<colgroup>
<col class="name">
<col class="year">
</colgroup>
<tr>
<th>Name</th>
<th>Year</th>
</tr>
<tr>
<td>Alice Moreno</td>
<td>2019</td>
</tr>
</table>
When browsers build a table's internal grid, each cell occupies one or more column slots. A cell with colspan="3" occupies three column slots, and columns are established based on the maximum number of slots any row uses. The validator checks that every column position in this grid has at least one cell whose starting position is in that column. If a column exists only because other cells span across it — but no cell ever begins there — the validator raises this warning.
This is a problem for several reasons:
- Accessibility: Screen readers use the table grid model to navigate cells and announce column headers. An empty or orphaned column confuses this navigation, making the table harder to understand for assistive technology users.
- Standards compliance: The HTML specification defines a precise table model. A column with no originating cell suggests a structural error in the table's markup.
- Rendering inconsistencies: Different browsers may handle these orphaned columns differently, leading to unpredictable layouts.
The most common causes are:
- Excessive
colspanvalues — a cell spans more columns than intended, creating extra columns that other rows don't fill. - Missing cells in a row — a row has fewer cells than the table's column count, leaving trailing columns empty.
- Incorrect
rowspancalculations — a cell spans rows, but subsequent rows still include cells for that column position, pushing other cells into non-existent columns or leaving gaps.
To fix the issue, count the total number of columns your table should have, then verify that every row's cells (accounting for colspan and active rowspan from previous rows) add up to exactly that number. Ensure each column position has at least one cell starting in it across all rows.
Examples
Incorrect: colspan creates a column no cell begins in
In this example, the first row establishes 3 columns. The second row spans all 3 with colspan="3". The third row only has 2 cells, so column 3 has no cell beginning in it.
<table>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
</tr>
<tr>
<td colspan="3">Team Alpha</td>
</tr>
<tr>
<td>Alice</td>
<td>Developer</td>
<!-- Column 3 has no cell beginning here -->
</tr>
</table>
Fixed: every row accounts for all columns
<table>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
</tr>
<tr>
<td colspan="3">Team Alpha</td>
</tr>
<tr>
<td>Alice</td>
<td>Developer</td>
<td>Active</td>
</tr>
</table>
Incorrect: excessive colspan creates extra columns
Here, the second row's colspan="4" establishes 4 columns, but no other row has a cell starting in column 4.
<table>
<tr>
<th>Q1</th>
<th>Q2</th>
<th>Q3</th>
</tr>
<tr>
<td colspan="4">Full year summary</td>
</tr>
<tr>
<td>100</td>
<td>200</td>
<td>300</td>
</tr>
</table>
Fixed: colspan matches the actual column count
<table>
<tr>
<th>Q1</th>
<th>Q2</th>
<th>Q3</th>
</tr>
<tr>
<td colspan="3">Full year summary</td>
</tr>
<tr>
<td>100</td>
<td>200</td>
<td>300</td>
</tr>
</table>
Incorrect: rowspan causes a missing cell origin
The rowspan="2" on "Alice" means the second row already has column 1 occupied. But the second row only provides one cell, leaving column 3 without a beginning cell in any row except the header.
<table>
<tr>
<th>Name</th>
<th>Task</th>
<th>Hours</th>
</tr>
<tr>
<td rowspan="2">Alice</td>
<td>Design</td>
<td>8</td>
</tr>
<tr>
<td>Code</td>
<!-- Column 1 is occupied by rowspan; column 3 has no cell -->
</tr>
</table>
Fixed: the spanned row includes the right number of cells
Since rowspan="2" on column 1 carries into the next row, that row only needs cells for columns 2 and 3.
<table>
<tr>
<th>Name</th>
<th>Task</th>
<th>Hours</th>
</tr>
<tr>
<td rowspan="2">Alice</td>
<td>Design</td>
<td>8</td>
</tr>
<tr>
<td>Code</td>
<td>6</td>
</tr>
</table>
A good practice is to sketch out your table grid on paper or in a spreadsheet before writing the HTML. Label each column slot and verify that every row fills all slots — either with a new cell or with a rowspan carry-over from a previous row. This makes it much easier to catch mismatched colspan and rowspan values before they cause validation errors.
The HTML specification requires that table structures be coherent — every column in a table must be "used" by at least one cell that starts in it. When you declare a <th> with colspan="2", you're telling the browser that the table has (at least) two columns. If the body rows don't provide cells to fill those columns, the table's structure becomes inconsistent.
This matters for several reasons. Screen readers and other assistive technologies rely on a well-formed table grid to navigate and announce cell contents. An inconsistent column structure can confuse these tools, leading to a poor experience for users who depend on them. Browsers may also render such tables unpredictably, since they have to guess how to handle the mismatch.
Common causes of this error include:
- A
colspanvalue on a header cell that exceeds the actual number of cells in body rows. - Empty
<tbody>,<thead>, or<tfoot>sections that leave declared columns without any cells. - Rows with fewer cells than other rows define, leaving some columns unoccupied.
- Copy-paste errors or template issues where rows were deleted but headers were left unchanged.
To fix this, examine your table's column structure. Count the total number of columns implied by each row (accounting for colspan and rowspan attributes) and make sure every row agrees on the total column count. Every column should have at least one cell beginning in it somewhere in the table.
Examples
Incorrect: colspan creates columns with no matching body cells
Here, the header declares two columns, but the body is empty, so column 2 has no cells beginning in it:
<table>
<thead>
<tr>
<th colspan="2">The table header</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Incorrect: Body rows have fewer cells than the header defines
The header spans three columns, but the body rows only have two cells each. Column 3 has no cells beginning in it:
<table>
<thead>
<tr>
<th colspan="3">Wide header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Cell 1</td>
<td>Cell 2</td>
</tr>
</tbody>
</table>
Correct: Body cells match the columns defined by the header
The header spans two columns, and the body row provides exactly two cells:
<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>
Correct: Three-column header with matching body cells
<table>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td>Developer</td>
<td>Active</td>
</tr>
</tbody>
</table>
Correct: Using colspan in body rows to fill all columns
If you need fewer visible cells in a body row, use colspan to span the remaining columns rather than leaving them empty:
<table>
<thead>
<tr>
<th>Name</th>
<th>Role</th>
<th>Status</th>
</tr>
</thead>
<tbody>
<tr>
<td>Alice</td>
<td colspan="2">Info unavailable</td>
</tr>
</tbody>
</table>
Correct: Reducing colspan to match actual content
If the header doesn't truly need to span multiple columns, simply remove the colspan:
<table>
<thead>
<tr>
<th>The table header</th>
</tr>
</thead>
<tbody>
<tr>
<td>The table body</td>
</tr>
</tbody>
</table>
When a table cell uses colspan to span multiple columns, the HTML specification requires that the columns being spanned actually exist and are accounted for in the table's column structure. If a cell's colspan creates columns that no other row has cells beginning in, the validator flags those empty columns. For example, if your widest row has 3 columns but another row contains a cell with colspan="6", columns 4 through 6 are established by that cell but are essentially phantom columns — no cell in any other row starts in them.
This matters for several reasons. Screen readers and assistive technologies rely on a coherent table structure to navigate cells and announce column/row relationships. An inconsistent column count can confuse these tools, leading to a poor experience for users who depend on them. Browsers may render the table without visible errors, but the underlying structure is invalid, which can cause unpredictable layout behavior across different rendering engines.
How to Fix
- Identify the offending row. Look for
<td>or<th>elements whosecolspanvalue creates more columns than the rest of the table defines. - Reduce the
colspanvalue so it matches the actual number of columns in the table. - Alternatively, add cells to other rows if you genuinely need more columns — make sure every column has at least one cell that begins in it.
A good rule of thumb: the colspan of any cell, combined with its starting column position, should never exceed the total column count of the table.
Examples
Incorrect: colspan exceeds the table's column count
This table has 2 columns (established by the first row), but the second row's colspan="5" tries to span 5 columns. Columns 3 through 5 have no cells beginning in them in any row.
<table>
<tr>
<td>First</td>
<td>Second</td>
</tr>
<tr>
<td colspan="5">Spans too many columns</td>
</tr>
</table>
Correct: colspan matches the table's column count
Set the colspan to 2 so the cell spans exactly the columns that exist.
<table>
<tr>
<td>First</td>
<td>Second</td>
</tr>
<tr>
<td colspan="2">Spans both columns</td>
</tr>
</table>
Incorrect: mixed rows with mismatched column counts
Here the first row establishes 3 columns, but the second row creates a cell starting at column 1 that spans 5 columns, leaving columns 4 and 5 with no cells beginning in them.
<table>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td colspan="5">Too wide</td>
</tr>
</table>
Correct: expand the table or reduce the span
Option A: Reduce the colspan to match the existing 3 columns.
<table>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td colspan="3">Spans all three columns</td>
</tr>
</table>
Option B: If you truly need 5 columns, add cells to the other rows so every column has a cell beginning in it.
<table>
<tr>
<td>A</td>
<td>B</td>
<td>C</td>
<td>D</td>
<td>E</td>
</tr>
<tr>
<td colspan="5">Spans all five columns</td>
</tr>
</table>
A <th> with a colspan wider than the rest of the table adds the columns in the reported range, and no <td> or <th> begins in any of them.
The validator builds the table grid from each row's cells and their colspan values. A <th colspan="4"> that starts in column 2 covers columns 2 to 5, so the table has at least five columns. The HTML table model requires every column to have at least one cell that starts in it, and a cell that only crosses a column through colspan doesn't count. If the other rows have only two cells, nothing starts in columns 3 to 5, and the validator reports them as the range 3…5, naming th as the element that created them.
This often happens with header rows that group headings over more columns than the body has, or with a colspan left over from a wider version of the table. The short rows usually add a warning too: "A table row was 2 columns wide, which is less than the column count established by the first row (5)." When only one column is empty, the validator names that single column ("Table column 3") instead of a range.
To fix it, lower the colspan so the header covers only the columns the rows use. If the table really needs the extra columns, add cells to the other rows so a cell starts in each of them.
Invalid example
The second heading spans four columns, but each body row has only two cells:
<table>
<tr>
<th>Term</th>
<th colspan="4">Dates</th>
</tr>
<tr>
<td>Autumn</td>
<td>September to December</td>
</tr>
</table>
Valid example
Without the colspan, the header and the body both have two columns:
<table>
<tr>
<th>Term</th>
<th>Dates</th>
</tr>
<tr>
<td>Autumn</td>
<td>September to December</td>
</tr>
</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