HTML Guides for h3
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 th element is specifically designed to represent a header cell in a table. It inherently conveys header semantics to browsers, screen readers, and other assistive technologies. When you place a heading element like h3 inside a th, you’re creating a structural conflict — the content is simultaneously acting as a table header and a document section heading. The HTML specification restricts the content model of th to “flow content, but with no header, footer, sectioning content, or heading content descendants.”
This matters for several reasons:
- Accessibility: Screen readers use heading elements to build a document outline and allow users to navigate between sections. A heading buried inside a table header cell disrupts this navigation, creating confusion about the page structure. The th element already communicates its role as a header through the table’s own semantics.
- Document structure: Headings define the hierarchical structure of a document. Placing them inside table cells implies that a new document section begins within the table, which is almost never the intended meaning.
- Standards compliance: Browsers may handle this invalid nesting inconsistently, leading to unpredictable rendering or accessibility tree representations.
The fix is straightforward: remove the heading element from inside the th. If the text inside the th needs to be visually larger or bolder, apply CSS styles directly to the th element or use a span with a class. If the heading was meant to title the entire table, move it outside the table or use the caption element.
Examples
❌ Incorrect: heading inside th
<table>
<tr>
<th>Month</th>
<th><h3>Revenue</h3></th>
</tr>
<tr>
<td>January</td>
<td>$500</td>
</tr>
</table>
The h3 inside the second th triggers the validation error.
✅ Fixed: remove the heading, use plain text
<table>
<tr>
<th>Month</th>
<th>Revenue</th>
</tr>
<tr>
<td>January</td>
<td>$500</td>
</tr>
</table>
The th element already communicates that “Revenue” is a header. No heading element is needed.
✅ Fixed: use CSS for visual styling
If the heading was used to make the text look bigger or styled differently, apply CSS to the th instead:
<table>
<tr>
<th>Month</th>
<th class="prominent">Revenue</th>
</tr>
<tr>
<td>January</td>
<td>$500</td>
</tr>
</table>
<style>
.prominent {
font-size: 1.2em;
font-weight: bold;
}
</style>
✅ Fixed: use caption for a table title
If the heading was meant to describe the entire table, use the caption element:
<table>
<caption>Monthly Revenue</caption>
<tr>
<th>Month</th>
<th>Revenue</th>
</tr>
<tr>
<td>January</td>
<td>$500</td>
</tr>
</table>
The caption element is the semantically correct way to provide a title or description for a table. You can style it with CSS to match the appearance of a heading. If you still need a heading in the document outline to precede the table, place it before the table element:
<h3>Revenue Report</h3>
<table>
<tr>
<th>Month</th>
<th>Revenue</th>
</tr>
<tr>
<td>January</td>
<td>$500</td>
</tr>
</table>
This approach keeps the document structure clean while maintaining proper table semantics. The same rule applies to all heading levels — h1, h2, h3, h4, h5, and h6 are all equally invalid inside th (and td) elements.
Ready to validate your sites?
Start your free trial today.