HTML Guides for header
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 rowgroup role represents a group of rows within a tabular structure — similar to what <thead>, <tbody>, or <tfoot> provide in a native HTML <table>. According to the ARIA specification, the rowgroup role should be used on elements that serve as structural containers for rows within a grid, table, or treegrid. A <header> element is not appropriate for this role because it carries its own strong semantic meaning (typically banner or a sectioning header), and overriding it with role="rowgroup" creates a conflict that the W3C validator flags.
This matters for several reasons. First, assistive technologies rely on correct role assignments to convey the structure of a page. When a <header> element is given role="rowgroup", screen readers receive contradictory signals about what the element represents, which can confuse users. Second, the HTML specification restricts which ARIA roles can be applied to certain elements — the <header> element does not allow rowgroup as a valid role override.
To fix this issue, you have two main options:
- Replace the <header> element with a <div> — since <div> has no implicit ARIA role, it freely accepts role="rowgroup".
- Use native HTML table elements — replace the custom ARIA table structure with <table>, <thead>, <tbody>, <tr>, <th>, and <td>, which provide the correct semantics without requiring any ARIA roles.
Examples
❌ Incorrect: role="rowgroup" on a <header> element
<div role="table" aria-label="Quarterly Sales">
<header role="rowgroup">
<div role="row">
<span role="columnheader">Quarter</span>
<span role="columnheader">Revenue</span>
</div>
</header>
<div role="rowgroup">
<div role="row">
<span role="cell">Q1</span>
<span role="cell">$1.2M</span>
</div>
</div>
</div>
The validator reports Bad value “rowgroup” for attribute “role” on element “header” because <header> cannot accept the rowgroup role.
✅ Fix option 1: Use a <div> instead of <header>
<div role="table" aria-label="Quarterly Sales">
<div role="rowgroup">
<div role="row">
<span role="columnheader">Quarter</span>
<span role="columnheader">Revenue</span>
</div>
</div>
<div role="rowgroup">
<div role="row">
<span role="cell">Q1</span>
<span role="cell">$1.2M</span>
</div>
</div>
</div>
A <div> is semantically neutral, so role="rowgroup" is perfectly valid on it.
✅ Fix option 2: Use native HTML table elements
<table>
<caption>Quarterly Sales</caption>
<thead>
<tr>
<th>Quarter</th>
<th>Revenue</th>
</tr>
</thead>
<tbody>
<tr>
<td>Q1</td>
<td>$1.2M</td>
</tr>
</tbody>
</table>
Native table elements like <thead> and <tbody> implicitly carry the rowgroup role, so no ARIA attributes are needed at all. This approach is generally preferred because it provides the best accessibility support out of the box and results in cleaner, more maintainable markup. Only use ARIA table roles when you cannot use native HTML tables (for example, when building a custom grid layout that requires non-table CSS).
The HTML specification defines built-in semantic roles for many elements, and the <header> element is one of them. When a <header> is a direct child of <body> (or at least not nested inside a sectioning element), browsers and assistive technologies already interpret it as a banner landmark — the region of the page that typically contains the site logo, navigation, and other introductory content. Explicitly adding role="banner" duplicates what the browser already knows, which adds unnecessary noise to your markup.
This principle is part of the WAI-ARIA specification’s guidance on using ARIA roles: the first rule of ARIA is “If you can use a native HTML element or attribute with the semantics and behavior you require already built in, instead of re-purposing an element and adding an ARIA role, state, or property to make it accessible, then do so.” Redundant roles don’t typically break anything, but they clutter the code, can confuse developers maintaining the project, and signal a misunderstanding of HTML semantics.
It’s worth noting an important nuance: the <header> element only maps to the banner role when it is not a descendant of <article>, <aside>, <main>, <nav>, or <section>. When nested inside one of these sectioning elements, <header> has no corresponding landmark role — it simply serves as the header for that particular section. In that context, adding role="banner" would not be redundant; it would actually change the semantics, which is almost certainly not what you want.
To fix the warning, remove the role="banner" attribute from your <header> element. The native semantics are sufficient.
Examples
Incorrect: redundant role="banner" on <header>
This triggers the validator warning because <header> already implies the banner role at the top level:
<header role="banner">
<img src="logo.svg" alt="My Company">
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
Correct: let <header> use its implicit role
Simply remove the role="banner" attribute:
<header>
<img src="logo.svg" alt="My Company">
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
Correct: using role="banner" on a non-<header> element
If for some reason you cannot use a <header> element (e.g., working within a legacy CMS), applying role="banner" to a <div> is the appropriate way to convey the same landmark semantics:
<div role="banner">
<img src="logo.svg" alt="My Company">
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</div>
A <header> inside a sectioning element has no banner role
When <header> is nested inside an <article> or other sectioning element, it does not carry the banner role. This is expected and correct — the <header> here simply introduces the article content:
<article>
<header>
<h2>Article Title</h2>
<p>Published on <time datetime="2024-01-15">January 15, 2024</time></p>
</header>
<p>Article content goes here.</p>
</article>
The <header> element represents introductory content for its nearest ancestor sectioning content or sectioning root element. It typically contains headings, logos, navigation, and search forms. The <footer> element represents a footer for its nearest ancestor sectioning content or sectioning root element, typically containing information like authorship, copyright data, or links to related documents.
The HTML specification states that <header> must not contain <header> or <footer> descendants. This restriction exists because these elements carry specific semantic meaning. A <footer> nested inside a <header> creates a contradictory document structure — it would simultaneously represent introductory content (by being in the header) and concluding/supplementary content (by being a footer). This confuses assistive technologies like screen readers, which use these landmark elements to help users navigate the page. When a screen reader encounters a <footer> inside a <header>, it cannot accurately convey the document structure to the user.
Note that this rule applies regardless of how deeply nested the <footer> is. Even if the <footer> is inside a <div> that is inside the <header>, it still violates the specification because it is a descendant of the <header>.
How to fix it
- Move the <footer> outside the <header> — Place it as a sibling element after the <header> closes.
- Replace <footer> with a non-semantic element — If you only need a visual container within the header (not actual footer semantics), use a <div> or <p> instead.
- Use a sectioning element as a boundary — If you genuinely need footer-like content within the header area, wrap it in a sectioning element like <section> or <article>. Because <footer> applies to its nearest sectioning ancestor, placing it inside a <section> within the <header> would technically satisfy the spec — but this approach should only be used when it makes semantic sense.
Examples
❌ Incorrect: <footer> nested inside <header>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<footer>
<p>© 2024 My Website</p>
</footer>
</header>
❌ Incorrect: deeply nested <footer> still inside <header>
<header>
<h1>My Website</h1>
<div class="header-bottom">
<footer>
<p>Contact us at info@example.com</p>
</footer>
</div>
</header>
✅ Correct: <footer> moved outside <header>
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
</header>
<footer>
<p>© 2024 My Website</p>
</footer>
✅ Correct: using a <div> for non-semantic content inside the header
<header>
<h1>My Website</h1>
<nav>
<a href="/">Home</a>
<a href="/about">About</a>
</nav>
<div class="header-meta">
<p>Contact us at info@example.com</p>
</div>
</header>
✅ Correct: <footer> inside a sectioning element within the header
<header>
<h1>Latest News</h1>
<article>
<h2>Featured Story</h2>
<p>A brief summary of the story...</p>
<footer>
<p>By Jane Doe, June 2024</p>
</footer>
</article>
</header>
In this last example, the <footer> is a descendant of the <article> element (a sectioning content element), so it acts as the footer for the article rather than for the <header>. This is valid because the spec forbids <footer> as a descendant of <header> only when there is no intervening sectioning content element.
The <footer> element represents footer content for its nearest ancestor sectioning element or the <body>. It typically contains information like copyright notices, contact details, or links to related documents. The <header> element, on the other hand, represents introductory content or a group of navigational aids. The HTML living standard states that <header> must not appear as a descendant of <footer>, because embedding introductory content inside closing content creates a semantic contradiction.
It’s worth noting that neither <header> nor <footer> are sectioning content themselves—they are flow content with specific usage restrictions. The <footer> element’s content model explicitly excludes <header> descendants at any depth, meaning you can’t nest a <header> inside a <footer> even if there are other elements in between.
This restriction matters for several reasons:
- Semantics and accessibility: Screen readers and assistive technologies rely on the correct use of landmark elements. A <header> inside a <footer> sends conflicting signals about the purpose of that content, which can confuse users navigating by landmarks.
- Standards compliance: Violating the content model rules means your HTML is invalid, which can lead to unpredictable behavior across different browsers and parsing engines.
- Maintainability: Using elements according to their intended purpose makes your markup easier for other developers to understand and maintain.
Examples
❌ Invalid: <header> nested inside <footer>
<footer>
<header>
<h2>Contact Us</h2>
<nav>
<a href="/email">Email</a>
<a href="/phone">Phone</a>
</nav>
</header>
<p>© 2024 Example Corp.</p>
</footer>
This triggers the validation error because <header> is a direct child of <footer>.
❌ Invalid: <header> deeply nested inside <footer>
<footer>
<div class="footer-top">
<header>
<h3>Quick Links</h3>
</header>
</div>
<p>© 2024 Example Corp.</p>
</footer>
The restriction applies to any level of nesting, not just direct children. A <header> anywhere inside a <footer> is invalid.
✅ Valid: <header> and <footer> as siblings
If the content is truly introductory, it belongs outside the <footer>:
<header>
<h2>Contact Us</h2>
<nav>
<a href="/email">Email</a>
<a href="/phone">Phone</a>
</nav>
</header>
<footer>
<p>© 2024 Example Corp.</p>
</footer>
✅ Valid: Using headings directly inside <footer>
If you need a heading inside a footer, use heading elements (<h2>, <h3>, etc.) directly without wrapping them in a <header>:
<footer>
<h2>Contact Us</h2>
<nav>
<a href="/email">Email</a>
<a href="/phone">Phone</a>
</nav>
<p>© 2024 Example Corp.</p>
</footer>
✅ Valid: Using a <div> for grouping inside <footer>
If you need to group content visually within a footer, use a <div> instead of a <header>:
<footer>
<div class="footer-top">
<h3>Quick Links</h3>
<nav>
<a href="/about">About</a>
<a href="/contact">Contact</a>
</nav>
</div>
<div class="footer-bottom">
<p>© 2024 Example Corp.</p>
</div>
</footer>
✅ Valid: <header> inside an <article> within a <footer>
One exception worth noting: a <header> can appear inside a <footer> if it belongs to a new sectioning element like <article> or <section> nested within that footer. In this case, the <header> is a descendant of the <article>, not semantically of the <footer>:
<footer>
<article>
<header>
<h3>Latest Blog Post</h3>
</header>
<p>A summary of the latest post.</p>
</article>
<p>© 2024 Example Corp.</p>
</footer>
This is valid because the <header> serves as introductory content for the <article>, and sectioning elements reset the scope of <header> and <footer> restrictions.
The <header> element has a specific content model restriction: it must not contain <header>, <footer>, or <main> elements as descendants. This means that not only direct children but any nested <header> — even one buried several levels deep inside other elements — will trigger this validation error.
This restriction exists because each <header> is supposed to introduce its surrounding sectioning content (like <article>, <section>, <nav>, or the <body> itself). If one <header> contains another, it becomes unclear which section each header is introducing. This ambiguity hurts accessibility, as screen readers rely on these landmarks to help users navigate the page structure. Assistive technologies may announce nested headers incorrectly or confuse users about where sections begin and end.
A common scenario that triggers this error is when a site-wide header wraps a component (like a card or widget) that has its own <header>. Another frequent mistake is accidentally duplicating <header> tags when copying markup or working with template partials.
To fix this issue, you have a few options:
- Move the inner <header> outside the outer one entirely.
- Place the inner <header> inside a sectioning element like <section> or <article> that is itself inside the outer <header> — though this is unusual and likely a sign of a structural problem.
- Replace the inner <header> with a non-landmark element like <div> if it doesn’t truly represent introductory content for a section.
Examples
Incorrect: nested <header> elements
This markup nests a <header> for a featured article directly inside the page’s <header>, which is invalid:
<header>
<h1>Welcome to Our Shop</h1>
<header>
<h2>Featured Product</h2>
<p>Check out our latest arrival!</p>
</header>
</header>
Correct: use a <div> for the inner grouping
If the inner content is simply a visual grouping within the same header, replace the nested <header> with a <div>:
<header>
<h1>Welcome to Our Shop</h1>
<div>
<h2>Featured Product</h2>
<p>Check out our latest arrival!</p>
</div>
</header>
Correct: move the inner <header> into its own sectioning element
If the inner <header> truly introduces a distinct section of content, move it into an <article> or <section> outside the page header:
<header>
<h1>Welcome to Our Shop</h1>
<nav>
<ul>
<li><a href="/toys">Toys</a></li>
<li><a href="/books">Books</a></li>
<li><a href="/shoes">Shoes</a></li>
</ul>
</nav>
</header>
<article>
<header>
<h2>Featured Product</h2>
<p>Check out our latest arrival!</p>
</header>
<p>Product details go here.</p>
</article>
Correct: deeply nested case with a sectioning element in between
A <header> can appear inside a sectioning element that is itself inside another <header>, because the inner <header> is no longer a descendant of the outer <header> in terms of the content model — wait, actually it still is a descendant. The spec says the <header> must not appear as a descendant at any depth. So the only valid fix is to ensure no <header> exists anywhere inside another <header>:
<!-- Invalid: even with an article in between, it's still nested -->
<header>
<article>
<header>
<h2>News</h2>
</header>
</article>
</header>
<!-- Valid: move the article outside the header -->
<header>
<h1>My Site</h1>
</header>
<article>
<header>
<h2>News</h2>
</header>
<p>Article content here.</p>
</article>
The key takeaway is straightforward: a <header> should never contain another <header>, regardless of how many elements sit between them. Restructure your HTML so each <header> lives in its own sectioning context, and your document will be valid, accessible, and semantically clear.
Ready to validate your sites?
Start your free trial today.