HTML Guides for empty
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.
An empty colspan on a <td> is invalid, because the attribute takes the number of columns the cell spans, a whole number from 1 to 1000.
Both colspan="" and a bare colspan with no value get this error. A value made only of spaces, like colspan=" ", gets a different one that starts with "Expected a digit".
Empty attributes like this usually come from a table builder in a CMS, or from a template that prints colspan="{{ cell.colspan }}" on every cell, whether or not the cell spans anything. The same templates often print rowspan="" too, which gets its own error saying "non-negative integer" instead, because rowspan also accepts 0.
Browsers treat an empty colspan as 1, the same as leaving the attribute out, so the table looks the same once you remove it. Change the template to print colspan only when the cell spans two or more columns.
Invalid example
<table>
<tr>
<th>Plan</th>
<th>Price</th>
</tr>
<tr>
<td colspan="">Basic</td>
<td colspan="">$10</td>
</tr>
<tr>
<td colspan="2">Prices include tax.</td>
</tr>
</table>
Valid example
<table>
<tr>
<th>Plan</th>
<th>Price</th>
</tr>
<tr>
<td>Basic</td>
<td>$10</td>
</tr>
<tr>
<td colspan="2">Prices include tax.</td>
</tr>
</table>
A colspan on a <th> has to say how many columns the header covers, as a whole number from 1 to 1000, so colspan="" is invalid.
Writing colspan with no value at all gives the same message. If the value holds only spaces, as in colspan=" ", the validator reports it differently, with a message that begins "Expected a digit".
Header cells often end up like this when a table plugin or theme writes the span attributes on every <th> and fills them from a setting that is blank for most columns. Check the same headers for rowspan="". The validator flags it separately, as "not a valid non-negative integer", because rowspan also accepts 0.
An empty colspan changes nothing on screen: browsers read it as 1, just as they do when the attribute is missing. Remove it from every header that sits over a single column, and keep a number only where a header groups several columns, such as colspan="2" above two related columns.
Invalid example
<table>
<tr>
<th colspan="">Course</th>
<th colspan="2">Schedule</th>
</tr>
<tr>
<td>Biology</td>
<td>Monday</td>
<td>Wednesday</td>
</tr>
</table>
Valid example
<table>
<tr>
<th>Course</th>
<th colspan="2">Schedule</th>
</tr>
<tr>
<td>Biology</td>
<td>Monday</td>
<td>Wednesday</td>
</tr>
</table>
The id attribute uniquely identifies an element within a document. According to the WHATWG HTML living standard, if the id attribute is specified, its value must be non-empty and must not contain any ASCII whitespace characters. The attribute itself is optional — you don't need to include it — but when you do, it must have a valid value. Setting id="" violates this rule because the empty string is not a valid identifier.
This issue commonly occurs when code is generated dynamically (e.g., by a templating engine or JavaScript framework) and the variable intended to populate the id value resolves to an empty string. It can also happen when developers add the attribute as a placeholder and forget to fill it in.
Why this matters
- Standards compliance: An empty
idviolates the HTML specification, making your document invalid. - Accessibility: Assistive technologies like screen readers rely on
idattributes to associate<label>elements with form controls. An emptyidbreaks this association, making forms harder to use for people who depend on these tools. - JavaScript and CSS: Methods like
document.getElementById("")and selectors like#(with no identifier) will not work as expected. An emptyidcan cause subtle, hard-to-debug issues in your scripts and styles. - Browser behavior: While browsers are generally forgiving, an empty
idleads to undefined behavior. Different browsers may handle it inconsistently.
How to fix it
- Assign a meaningful value: Give the
ida descriptive, unique value that identifies the element's purpose (e.g.,id="country-select"). - Remove the attribute: If you don't need the
id, simply remove it from the element altogether. - Fix dynamic generation: If a templating engine or framework is producing the empty value, add a conditional check to either output a valid
idor omit the attribute entirely.
Examples
❌ Incorrect: empty id attribute
<label for="country">Country</label>
<select id="" name="country">
<option value="us">United States</option>
<option value="ca">Canada</option>
</select>
This triggers the validation error because id="" is an empty string.
✅ Correct: meaningful id value
<label for="country">Country</label>
<select id="country" name="country">
<option value="us">United States</option>
<option value="ca">Canada</option>
</select>
The id now has a valid, non-empty value, and the <label> element's for attribute correctly references it.
✅ Correct: id attribute removed entirely
<label>
Country
<select name="country">
<option value="us">United States</option>
<option value="ca">Canada</option>
</select>
</label>
If you don't need the id, remove it. Here, the <label> wraps the <select> directly, so the for/id association isn't needed — the implicit label works just as well.
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>
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