Skip to main content
HTML Validation

The element “h3” must not appear as a descendant of the “th” element.

About This HTML Issue

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.

Find issues like this automatically

Rocket Validator scans thousands of pages in seconds, detecting HTML issues across your entire site.

Help us improve our guides

Was this guide helpful?

Ready to validate your sites?
Start your free trial today.