HTML Guides for nesting
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 HTML specification defines a strict content model for the <ul> (unordered list) element: its permitted content is zero or more <li> elements, optionally intermixed with <script> and <template> elements. A <div> is not among these allowed children, so placing one directly inside a <ul> produces a validation error.
This issue commonly arises when developers try to group or wrap list items for styling or layout purposes. For example, you might want to add a container around certain <li> elements for flexbox or grid alignment, or you might be using a templating system that injects wrapper <div> elements into your list markup.
Why this matters
- Browser parsing inconsistencies: When browsers encounter invalid nesting, they attempt to fix the DOM structure automatically, but different browsers may handle it differently. This can lead to unexpected rendering where list items appear outside their intended container or styles break unpredictably.
- Accessibility: Screen readers and assistive technologies rely on correct semantic structure to convey list relationships to users. A <div> breaking the <ul> → <li> relationship can cause assistive tools to misinterpret or skip list content entirely.
- Standards compliance: Invalid HTML can cause cascading parser errors — note that the validator message says “Suppressing further errors from this subtree,” meaning additional issues within that structure may be hidden from you.
How to fix it
- Move the <div> inside the <li>: If you need a wrapper for styling, place it inside the list item rather than around it.
- Remove the <div> entirely: If it serves no purpose, simply remove it and let the <li> elements sit directly inside the <ul>.
- Use CSS on the <li> elements: In many cases, you can apply the styles you need directly to the <li> elements without an extra wrapper.
- Use role="list" on a <div> parent: If your layout truly requires <div> wrappers, consider restructuring with ARIA roles, though native semantic elements are always preferred.
Examples
❌ Incorrect: <div> as a direct child of <ul>
<ul>
<div>
<li>Apples</li>
<li>Bananas</li>
</div>
<div>
<li>Carrots</li>
<li>Dates</li>
</div>
</ul>
✅ Correct: Move the <div> inside each <li>
<ul>
<li><div>Apples</div></li>
<li><div>Bananas</div></li>
<li><div>Carrots</div></li>
<li><div>Dates</div></li>
</ul>
✅ Correct: Remove the <div> entirely
<ul>
<li>Apples</li>
<li>Bananas</li>
<li>Carrots</li>
<li>Dates</li>
</ul>
❌ Incorrect: Using a <div> as a styling wrapper around list items
<ul class="product-list">
<div class="row">
<li>Product A</li>
<li>Product B</li>
<li>Product C</li>
</div>
</ul>
✅ Correct: Apply layout styles directly to the <ul> and <li> elements
<ul class="product-list row">
<li>Product A</li>
<li>Product B</li>
<li>Product C</li>
</ul>
❌ Incorrect: Template or component wrapper inserting a <div>
This often happens in frameworks where a component renders a wrapping <div>:
<ul>
<div class="list-item-wrapper">
<li>Item 1</li>
</div>
<div class="list-item-wrapper">
<li>Item 2</li>
</div>
</ul>
✅ Correct: Move the wrapper class to the <li> itself
<ul>
<li class="list-item-wrapper">Item 1</li>
<li class="list-item-wrapper">Item 2</li>
</ul>
The same rule applies to <ol> (ordered list) elements — they share the same content model restriction. Always ensure that <li> is the direct child of <ul> or <ol>, and place any additional wrapper elements inside the <li> rather than around it.
HTML elements follow strict nesting rules defined by the WHATWG HTML Living Standard. Every element has a content model — a description of what content (text, elements, or both) it may contain. When you place an element somewhere it isn’t allowed, the browser must guess your intent and may restructure the DOM in unexpected ways. This can lead to inconsistent rendering across browsers, broken layouts, and accessibility issues for screen readers and other assistive technologies.
The “(Suppressing further errors from this subtree.)” part of the message means the validator has stopped checking anything nested inside the problematic element. This is important — it means there could be additional errors hidden beneath this one. Fixing this nesting issue may reveal further problems that need attention.
Here are some of the most common cases that trigger this error:
- Block elements inside inline elements: Placing a <div> inside a <span> or an <a> that doesn’t permit flow content in that context.
- Invalid list children: Putting <div>, <p>, or other elements directly inside <ul> or <ol>, which only allow <li> (and <script>/<template>) as direct children.
- Invalid table structure: Placing <td> directly inside <table> without wrapping it in <tr>, or putting non-table elements where only <thead>, <tbody>, <tfoot>, or <tr> are expected.
- Headings or paragraphs inside <p>: The <p> element only accepts phrasing content, so nesting a <h2> or another <p> inside it is invalid.
- Interactive elements inside interactive elements: Nesting a <button> inside an <a>, or an <a> inside a <button>.
To fix the issue, consult the MDN documentation for the parent element and check its Permitted content section. Then either move the child element to a valid location, wrap it in an appropriate intermediary element, or replace the parent or child with a more suitable element.
Examples
Invalid list children
A <ul> only permits <li> elements as direct children.
❌ Incorrect:
<ul>
<div>
<li>Item one</li>
<li>Item two</li>
</div>
</ul>
✅ Correct:
<ul>
<li>Item one</li>
<li>Item two</li>
</ul>
Block element inside a paragraph
The <p> element only accepts phrasing content. A <div> is flow content and cannot be nested inside it.
❌ Incorrect:
<p>
Here is some text.
<div class="highlight">This is highlighted.</div>
</p>
✅ Correct:
<p>Here is some text.</p>
<div class="highlight">This is highlighted.</div>
Or use a <span> if you want inline styling within the paragraph:
<p>
Here is some text.
<span class="highlight">This is highlighted.</span>
</p>
Invalid table structure
Table cells (<td>) must be inside a <tr>, which itself must be inside <thead>, <tbody>, <tfoot>, or directly inside <table>.
❌ Incorrect:
<table>
<td>Name</td>
<td>Age</td>
</table>
✅ Correct:
<table>
<tr>
<td>Name</td>
<td>Age</td>
</tr>
</table>
Interactive elements nested inside interactive elements
A <button> cannot be placed inside an <a> element, and vice versa, because interactive content cannot nest inside other interactive content.
❌ Incorrect:
<a href="/dashboard">
<button>Go to Dashboard</button>
</a>
✅ Correct (choose one or the other):
<a href="/dashboard">Go to Dashboard</a>
Or style a link to look like a button using CSS:
<a href="/dashboard" class="button">Go to Dashboard</a>
Wrapping elements inside <select>
The <select> element only allows <option>, <optgroup>, and scripting elements as children.
❌ Incorrect:
<select>
<div>
<option>Apple</option>
<option>Banana</option>
</div>
</select>
✅ Correct:
<select>
<optgroup label="Fruits">
<option>Apple</option>
<option>Banana</option>
</optgroup>
</select>
The HTML specification explicitly forbids nesting <a> elements inside other <a> elements. This is defined as part of the content model for the <a> element — it is “transparent” but must not contain any interactive content, which includes other <a> elements. When the validator encounters a closing </a> tag that would violate these nesting rules, it raises this error.
This typically happens in one of two scenarios:
- A missing closing </a> tag — You forget to close one link, so the next link appears to be nested inside it.
- Intentionally wrapping one link inside another — You try to place a clickable link inside a larger clickable area, which is invalid HTML.
Why this matters
When an <a> element is nested inside another <a> element, browsers must guess what you intended. Different browsers may handle this differently — some will auto-close the first link before starting the second, while others may produce unexpected DOM structures. This leads to:
- Unpredictable behavior — Click targets may not work as expected across different browsers.
- Accessibility issues — Screen readers rely on a well-structured DOM. Ambiguous nesting confuses assistive technologies and makes navigation difficult for users who depend on them.
- Broken styling — CSS selectors that depend on proper parent-child relationships may not apply correctly.
How to fix it
- Find the offending <a> tags — The validator will point to the line with the problematic closing </a>. Look at that line and the lines above it to find where the nesting issue begins.
- Add missing closing tags — If you forgot a </a>, add it before the next <a> opens.
- Restructure if needed — If you intended to have a link inside a larger clickable area, redesign the markup so that the links are siblings rather than nested.
Examples
❌ Missing closing tag causes implicit nesting
The first <a> is never closed, so the second <a> appears to be nested inside it:
<nav>
<a href="one.html">Page 1
<a href="two.html">Page 2</a>
</nav>
✅ Fixed by adding the missing closing tag
<nav>
<a href="one.html">Page 1</a>
<a href="two.html">Page 2</a>
</nav>
❌ Intentionally nesting links (invalid)
Wrapping a link inside a larger link is not allowed, even if it seems useful for UI purposes:
<a href="/article">
<h2>Article Title</h2>
<p>A short summary of the article.</p>
<a href="/author">Author Name</a>
</a>
✅ Fixed by restructuring with sibling links
Use CSS positioning or a different layout strategy to achieve the same visual result without nesting:
<article>
<a href="/article">
<h2>Article Title</h2>
<p>A short summary of the article.</p>
</a>
<p>By <a href="/author">Author Name</a></p>
</article>
❌ Forgetting to close links in a list
This is especially common in navigation menus built with lists:
<ul>
<li><a href="/home">Home</li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
Here, the first <a> is never closed. The </li> tag implicitly closes the <li>, but the <a> remains open, causing nesting issues with the subsequent links.
✅ Fixed by properly closing each link
<ul>
<li><a href="/home">Home</a></li>
<li><a href="/about">About</a></li>
<li><a href="/contact">Contact</a></li>
</ul>
A good habit is to write both the opening and closing <a> tags together before filling in the content. This prevents accidental omission and keeps your HTML well-structured.
HTML follows strict nesting rules: when one element is opened inside another, the inner element must be closed before the outer one. This is sometimes called the “last opened, first closed” principle. When a </b> end tag appears while another element that was opened inside the <b> is still open, the validator reports this nesting violation.
This matters for several reasons. First, browsers must guess what you intended when they encounter improperly nested tags, and different browsers may interpret the structure differently, leading to inconsistent rendering. Second, assistive technologies like screen readers rely on a well-formed DOM tree to convey the correct meaning and structure of content to users. Misnested tags can produce a confusing or broken experience. Third, improperly nested elements can cause unexpected behavior with CSS styling, since the computed DOM tree may not match what you wrote in your source code.
The fix is straightforward: always close elements in the exact reverse order you opened them. If <b> is opened first and <a> is opened second, then </a> must come before </b>.
Examples
Incorrect: <b> closed before a nested <a>
<p><b><a href="/about">About us</b></a></p>
Here, the <a> element was opened inside the <b>, but </b> appears before </a>. This violates the nesting rules.
Correct: inner element closed first
<p><b><a href="/about">About us</a></b></p>
The <a> is closed first, then the <b>, respecting the order in which they were opened.
Incorrect: multiple nesting violations
<p><b><em><a href="#">Click here</b></em></a></p>
Three elements are opened (<b>, then <em>, then <a>), but they are closed in the wrong order.
Correct: proper reverse-order closing
<p><b><em><a href="#">Click here</a></em></b></p>
The elements close in reverse order: </a> first, then </em>, then </b>.
Incorrect: <b> overlapping with a block-level element
<b><p>Bold paragraph</b></p>
Beyond the nesting order issue, note that <b> is a phrasing (inline) element and should not wrap <p> (a flow/block element). This is a separate but related violation.
Correct: <b> inside the paragraph
<p><b>Bold paragraph</b></p>
The <b> element is now properly placed inside the <p>, and the nesting order is correct.
A helpful mental model
Think of HTML nesting like parentheses in math. Every opening must have a corresponding close, and they cannot cross:
Wrong: ( [ ) ]
Right: ( [ ] )
Translating to HTML:
<!-- Wrong -->
<b><em>text</b></em>
<!-- Right -->
<b><em>text</em></b>
If you are working with complex or deeply nested markup, using a code editor with auto-closing tags and bracket matching can help you spot these issues before they reach the validator.
The <code> element is an inline-level (phrasing content) element designed to represent a fragment of computer code. According to the HTML specification, it can only contain other phrasing content — elements like <span>, <em>, <strong>, <a>, and text nodes. It cannot contain block-level (flow content) elements such as <div>, <p>, <ul>, <h1>–<h6>, or <table>.
When the validator reports that an end tag </code> violates nesting rules, it means one of two things is happening:
-
Disallowed content inside <code>: A block-level element has been placed inside the <code> element. When the browser encounters a block-level element where only phrasing content is allowed, it may implicitly close the <code> element. The subsequent </code> end tag then has no matching open tag, causing the nesting violation.
-
Overlapping or misnested tags: Tags inside <code> are improperly overlapped, meaning an element opened inside <code> is closed outside it, or vice versa.
This matters for several reasons. Browsers will attempt to “fix” the broken nesting by rearranging the DOM in ways you may not expect, leading to inconsistent rendering and styling. Screen readers and other assistive technologies rely on a well-formed DOM tree, so broken nesting can harm accessibility. Additionally, other validator errors in your document may cascade from this single nesting issue, so fixing it can resolve multiple warnings at once.
When debugging this error, look at other validation errors reported near the same line. Often, a prior error — such as an unclosed tag or an unexpected block element — is the root cause, and the </code> nesting violation is a downstream consequence.
Examples
❌ Block-level element inside <code>
Placing a <div> inside <code> violates the content model. The browser implicitly closes <code> before the <div>, leaving the </code> end tag orphaned.
<p>Example: <code>some text <div>block content</div> more text</code></p>
✅ Use only phrasing content inside <code>
Replace the block-level element with an inline alternative like <span>:
<p>Example: <code>some text <span>inline content</span> more text</code></p>
❌ Overlapping tags with <code>
Here, <em> is opened inside <code> but closed after </code>, creating an overlap:
<p>See <code>myFunction(<em>arg</code>)</em> for details.</p>
✅ Properly nested tags
Ensure every element opened inside <code> is also closed inside it:
<p>See <code>myFunction(<em>arg</em>)</code> for details.</p>
❌ Paragraph inside <code>
A <p> element is not allowed inside <code>:
<code>
<p>First line of code</p>
<p>Second line of code</p>
</code>
✅ Use <pre><code> for multi-line code blocks
For multi-line code, wrap <code> inside a <pre> element and use line breaks instead of paragraphs:
<pre><code>First line of code
Second line of code</code></pre>
❌ List inside <code>
<code>
<ul>
<li>step one</li>
<li>step two</li>
</ul>
</code>
✅ Separate the list from the code markup
Use <code> individually around the inline code portions:
<ul>
<li><code>step one</code></li>
<li><code>step two</code></li>
</ul>
How to Fix
- Find the line referenced by the validator error and look at what’s inside the <code> element.
- Check for block-level elements like <div>, <p>, <ul>, <table>, or headings nested inside <code>. Replace them with phrasing content alternatives or restructure your markup.
- Check for overlapping tags where an element started inside <code> is closed outside it (or the reverse). Make sure every tag opened inside <code> is closed inside it.
- Review related errors in the validator output. Often, fixing an earlier nesting or unclosed-tag error will resolve the </code> violation automatically.
HTML requires elements to be properly nested, meaning you must close child elements before closing their parent elements. When an </em> end tag appears in the wrong place — such as before an inner element has been closed, or after an outer element has already been closed — the browser encounters overlapping tags that violate the HTML specification. This is sometimes called “tag soup.”
Browsers attempt to recover from overlapping tags, but the way they do so is unpredictable and may not match your intent. One browser might auto-close the inner element, while another might restructure the DOM differently. This can lead to inconsistent rendering, broken styles, and unexpected behavior across browsers. It also creates problems for assistive technologies like screen readers, which rely on a well-formed document tree to convey meaning to users.
The nesting rule is straightforward: elements must close in the reverse order they were opened. If you open <em> and then open <a>, you must close </a> first, then </em>. Think of it like stacking boxes — you can’t remove a box from the bottom without first removing the one on top.
This issue can also arise when <em> is used across block-level boundaries. For example, wrapping <em> around multiple <p> elements or closing </em> inside a <div> when it was opened outside of it will also trigger this error.
Examples
Overlapping with an inline element
The </em> tag closes before the nested <a> tag, creating overlapping elements:
<!-- ❌ Wrong: <em> closes before <a> -->
<p><em><a href="#">link</em></a></p>
Close the inner <a> element first, then the outer <em>:
<!-- ✅ Correct: tags close in reverse order -->
<p><em><a href="#">link</a></em></p>
Overlapping with a block-level element
The <em> element spans across a <p> boundary, which is not allowed:
<!-- ❌ Wrong: <em> opened in one <p> and closed in another -->
<p>This is <em>emphasized text</p>
<p>that continues here</em> in a new paragraph.</p>
Apply <em> separately within each <p> element:
<!-- ✅ Correct: <em> is properly contained within each <p> -->
<p>This is <em>emphasized text</em></p>
<p><em>that continues here</em> in a new paragraph.</p>
Multiple levels of nesting
With deeply nested elements, every tag must still close in strict reverse order:
<!-- ❌ Wrong: </em> closes before </strong> -->
<p><em><strong>bold and italic</em></strong></p>
<!-- ✅ Correct: </strong> closes first, then </em> -->
<p><em><strong>bold and italic</strong></em></p>
<em> crossing a <div> boundary
<!-- ❌ Wrong: <em> opened outside <div>, closed inside -->
<em>
<div>
<p>Some content</p>
</em>
</div>
Keep the <em> element entirely inside or outside the block element:
<!-- ✅ Correct: <em> is fully contained within the <div> -->
<div>
<p><em>Some content</em></p>
</div>
How to spot and fix these errors
- Read the error message carefully. The W3C validator usually tells you which line the problem is on and which tags are involved.
- Match every opening tag with its closing tag. Trace through the nesting to make sure each pair is properly contained within its parent.
- Use consistent indentation. Properly indented code makes nesting issues much easier to see at a glance.
- Check for copy-paste errors. Overlapping tags often sneak in when code is moved between elements without updating the surrounding tags.
End tag “i” violates nesting rules because the closing </i> does not match the most recently opened still-unclosed inline element, causing mis-nested tags.
HTML requires elements to be properly nested in a stack-like order: last opened, first closed. Inline elements like the i element (for idiomatic text), em, strong, a, and span must not overlap. When you open i and then open b, you must close b before closing i. Mis-nesting often happens around links or emphasis tags, e.g., i inside a but closed outside. The i element is purely presentational/idiomatic; consider em for emphasis or CSS with font-style: italic;, but whichever you use, keep the nesting consistent.
Common patterns that trigger the error:
- Overlapping inline elements: i … b … </i> … </b>
- Closing order mismatch across a, span, em, strong, i
- Copy/paste around icons or screen-reader text
Fix by reordering the tags so they close in reverse order of opening, or by merging styles into one element to avoid overlaps.
HTML Examples
Incorrect (reproduces the validator error)
<p>
<a href="/about"><i>About <strong>Us</i></strong></a>
</p>
Correct (properly nested)
<p>
<a href="/about"><i>About <strong>Us</strong></i></a>
</p>
HTML follows a strict nesting model where elements must be properly contained within one another. When you open a <strong> element and then open another element inside it (such as an <a>, <em>, or <span>), you must close the inner element first before closing </strong>. Closing tags out of order creates overlapping elements, which violates the HTML specification.
This matters for several important reasons. First, browsers must guess how to interpret improperly nested markup, and different browsers may resolve the ambiguity differently, leading to inconsistent rendering. Second, assistive technologies like screen readers rely on a well-formed document tree to convey the correct structure and emphasis to users. Overlapping tags produce a broken DOM tree that can confuse these tools. Third, the WHATWG HTML specification explicitly defines the parsing model as a tree structure — elements cannot partially overlap because a tree node can only have one parent.
The fix is straightforward: always close elements in the reverse order they were opened. Think of it as a “last opened, first closed” rule. If <strong> is opened first and <a> is opened second, then </a> must come before </strong>.
Examples
Incorrect: overlapping tags
The </strong> tag closes before the inner <a> tag, violating nesting rules:
<p><strong><a href="/about">About us</strong></a></p>
Correct: properly nested tags
The <a> element is fully closed before </strong>:
<p><strong><a href="/about">About us</a></strong></p>
Incorrect: multiple nested elements closed out of order
Here <strong> overlaps with both <em> and <a>:
<p><strong><em><a href="#">Learn more</strong></em></a></p>
Correct: closing in reverse order
Each tag is closed in the exact reverse order it was opened:
<p><strong><em><a href="#">Learn more</a></em></strong></p>
Incorrect: strong spanning across block-level boundaries
Sometimes the nesting violation occurs when <strong> wraps across list items or other structures:
<ul>
<li><strong>First item</li>
<li>Second item</strong></li>
</ul>
Correct: apply strong within each element individually
Keep <strong> fully contained within each <li>:
<ul>
<li><strong>First item</strong></li>
<li><strong>Second item</strong></li>
</ul>
A helpful way to spot these issues is to visually trace your opening and closing tags — if you draw lines connecting each pair, the lines should never cross. If they do, you have a nesting violation that needs to be reordered.
According to the HTML specification, heading elements (h1–h6) have a content model of “phrasing content,” which means they can only contain inline-level elements like span, strong, em, a, and text nodes. Other heading elements are not phrasing content — they are flow content — so placing one heading inside another is invalid HTML.
This matters for several reasons. Screen readers and other assistive technologies rely on a well-formed heading hierarchy to help users navigate a page. When headings are nested inside each other, the document outline becomes broken and confusing, making it harder for users to understand the structure of the content. Browsers may also attempt to “fix” the invalid markup by auto-closing the outer heading before starting the inner one, which can produce unexpected rendering and DOM structures that differ from what you intended.
There are two common causes of this error:
-
Intentionally nesting headings for styling. Developers sometimes nest an h2 inside an h1 hoping to create a visual “main heading + subtitle” pattern. This is invalid. Instead, use separate heading elements or use a span or p element for the subtitle.
-
A missing or malformed closing tag. If you accidentally write <h3> instead of </h3> for a closing tag, the browser sees two opening h3 tags in a row. The first heading is never properly closed, and the second heading appears to be nested inside it.
Examples
❌ Heading nested inside another heading
<h1>Main heading
<h2>Sub heading</h2>
</h1>
The h2 is a child of the h1, which is not allowed. To create a heading with a subtitle, use separate elements:
✅ Headings as siblings
<h1>Main heading</h1>
<h2>Sub heading</h2>
Or, if the subtitle should be part of a sectioned document structure:
<main>
<h1>Main heading</h1>
<section>
<h2>Section heading</h2>
<p>Paragraph content</p>
</section>
</main>
❌ Missing closing slash causes nesting
A very common typo is forgetting the / in the closing tag:
<h3>Meet the Feebles<h3>
<h3>Bad Taste<h3>
Here, <h3>Meet the Feebles<h3> opens a second h3 instead of closing the first one. The validator sees the second h3 as a child of the first. The same problem cascades to subsequent headings.
✅ Properly closed heading tags
<h3>Meet the Feebles</h3>
<h3>Bad Taste</h3>
❌ Using nested headings for visual hierarchy inside a heading
<h1>
Our Company
<h3>Established 1999</h3>
</h1>
✅ Using a span for supplementary text within a heading
<h1>
Our Company
<span class="subtitle">Established 1999</span>
</h1>
You can then style the .subtitle class with CSS to achieve the desired visual appearance — for example, displaying it on a new line with a smaller font size:
.subtitle {
display: block;
font-size: 0.5em;
font-weight: normal;
}
✅ Using the hgroup element
The hgroup element is specifically designed for grouping a heading with related content like subtitles:
<hgroup>
<h1>Our Company</h1>
<p>Established 1999</p>
</hgroup>
This keeps the heading hierarchy clean while semantically associating the subtitle with the heading. The hgroup element is supported in the current HTML living standard and works well with assistive technologies.
Nested comments are not allowed in HTML. When you place an opening comment tag <!-- within an existing comment, it causes a parsing error.
To fix this issue, you should avoid nesting comments. If you need to include multiple comments in your HTML code, you can separate them or consider alternative ways to convey the information without nested comments.
Here’s an example of a nested comments, which is not allowed in HTML:
<!-- This is a valid comment -->
<!-- This <!-- is not allowed -->
nested comment -->
To fix the nested comment issue, you can rewrite the comments like this:
<!-- This is a valid comment -->
<!-- Avoid nesting comments and provide comments separately -->
<!-- Another comment here -->
The HTML specification defines <a> elements as having a transparent content model, but with specific exceptions — most notably, they must not contain interactive content, which includes other <a> elements. This means you can never legally nest one link inside another, regardless of how deeply nested or how the markup is structured.
This error most commonly occurs for one of two reasons:
- A missing closing tag: You forgot to close a previous <a> element with </a>, so the browser (and the validator) considers the next <a> tag to be nested inside the still-open one.
- Intentionally nested links: You tried to place a link inside another link, perhaps to create a card component where both the card and an inner element are clickable.
Why this matters
- Unpredictable browser behavior: When browsers encounter nested <a> elements, they attempt to fix the invalid markup using error-recovery algorithms, but different browsers may handle it differently. This can lead to broken links, missing content, or unexpected DOM structures.
- Accessibility issues: Screen readers and other assistive technologies rely on a well-formed DOM. Nested links create confusing navigation — a user tabbing through links may encounter unexpected behavior or miss content entirely.
- Standards compliance: The WHATWG HTML specification explicitly states that <a> elements must not have interactive content descendants, including other <a> elements.
Examples
Missing closing tag (most common cause)
The most frequent trigger is simply forgetting to close an <a> tag. The validator sees the second <a> as being inside the first:
<!-- ❌ Bad: first <a> is never closed -->
<nav>
<a href="one.html">Page 1
<a href="two.html">Page 2</a>
</nav>
Add the missing </a> to fix it:
<!-- ✅ Good: both <a> elements are properly closed -->
<nav>
<a href="one.html">Page 1</a>
<a href="two.html">Page 2</a>
</nav>
Intentionally nested links
Sometimes developers try to nest links when building clickable card components:
<!-- ❌ Bad: <a> nested inside another <a> -->
<a href="/article" class="card">
<h2>Article Title</h2>
<p>A short description of the article.</p>
<a href="/author">Author Name</a>
</a>
There are several valid approaches to fix this. One common pattern is to make the card a non-link container and use CSS to stretch the primary link over the entire card:
<!-- ✅ Good: no nested links, card is still fully clickable -->
<div class="card">
<h2><a href="/article" class="card-link">Article Title</a></h2>
<p>A short description of the article.</p>
<a href="/author">Author Name</a>
</div>
.card {
position: relative;
}
.card-link::after {
content: "";
position: absolute;
inset: 0;
}
.card a:not(.card-link) {
position: relative;
z-index: 1;
}
This technique uses a pseudo-element to expand the primary link’s clickable area over the entire card, while the secondary link (Author Name) sits above it via z-index, remaining independently clickable.
Links wrapping block-level content
In HTML5, <a> elements can wrap block-level elements like <div> and <h2>, which is perfectly valid. Just make sure you don’t accidentally nest another <a> inside:
<!-- ✅ Good: <a> wrapping block content with no nested links -->
<a href="/article">
<div class="card">
<h2>Article Title</h2>
<p>A short description of the article.</p>
</div>
</a>
Quick checklist
- Search your HTML for every <a tag and verify it has a corresponding </a>.
- If you’re generating HTML dynamically (with a CMS, templating engine, or JavaScript), check that your template logic doesn’t produce unclosed or nested anchors.
- If you need multiple clickable areas within a single component, use the CSS pseudo-element overlay technique shown above instead of nesting links.
The HTML specification explicitly forbids nesting interactive content inside a <button> element. This means a <button> cannot contain another <button>, nor can it contain elements like <a>, <input>, <select>, <textarea>, or any other interactive element. The <button> element’s content model allows phrasing content, but specifically excludes interactive content.
The most common cause of this error is a missing </button> closing tag. When you forget to close a button, the parser considers everything that follows — including the next <button> start tag — as being inside the first button. This creates an invalid nesting situation even though you likely intended the buttons to be siblings.
This matters for several reasons:
- Accessibility: Screen readers and assistive technologies rely on proper document structure. A button nested inside another button creates a confusing interaction model — which button does the user activate when they click or press Enter?
- Browser behavior: Browsers handle this invalid markup inconsistently. Some may ignore the inner button, while others may attempt error recovery in unpredictable ways, leading to broken functionality.
- Standards compliance: Invalid HTML can interfere with JavaScript event handling, CSS styling, and overall page reliability.
Examples
Missing closing tag (triggers the error)
<button>Submit
<button>Cancel</button>
Here, the first <button> is never closed, so the parser sees the second <button> as being nested inside it.
Intentionally nested buttons (triggers the error)
<button class="card">
<span>Select this plan</span>
<button class="details">More info</button>
</button>
Even if this nesting is intentional, it is invalid HTML. A <button> cannot contain another <button>.
Fix: Close each button properly
<button>Submit</button>
<button>Cancel</button>
Adding the missing </button> tag makes the two buttons proper siblings.
Fix: Restructure nested interactive elements
If you need a clickable card with an additional action inside it, separate the interactive elements rather than nesting them:
<div class="card">
<button class="select">Select this plan</button>
<button class="details">More info</button>
</div>
Fix: Use non-interactive elements for styling purposes
If the inner element was only meant for visual grouping, use a <span> or other phrasing element instead of a <button>:
<button class="card">
<span class="label">Select this plan</span>
<span class="sublabel">Best value</span>
</button>
This keeps a single interactive <button> while using non-interactive <span> elements for internal structure and styling.
The <iframe> element embeds an entirely separate HTML document within the current page, creating its own independent browsing context. The <a> element, on the other hand, is an interactive element designed to navigate users to a new URL or location. When you nest an <iframe> inside an <a>, browsers face a conflict: user interactions like clicks could be intended for the embedded content inside the iframe or for the link itself. The HTML specification resolves this ambiguity by simply disallowing it.
According to the WHATWG HTML living standard, the <a> element’s content model does not permit interactive content as descendants. The <iframe> element is categorized as interactive content, which means it must not appear anywhere inside an <a> tag — not as a direct child and not nested deeper within other elements inside the link.
This restriction matters for several reasons:
- Accessibility: Screen readers and assistive technologies cannot reliably convey the purpose of a link that contains an embedded document. Users may not understand whether they are interacting with the link or the iframe.
- Unpredictable behavior: Different browsers may handle clicks on the iframe-inside-a-link differently, leading to inconsistent user experiences.
- Standards compliance: Violating the content model makes your HTML invalid, which can cause unexpected rendering and behavior.
To fix the issue, restructure your markup so the <iframe> and <a> are siblings or otherwise separated. If your goal is to provide a link alongside embedded content, place the link before or after the iframe. If you want a clickable preview that links somewhere, consider using an image thumbnail inside the link instead of an iframe.
Examples
❌ Invalid: <iframe> inside an <a> element
<a href="https://example.com">
<iframe src="https://example.com/embed"></iframe>
</a>
This triggers the validation error because the <iframe> is a descendant of the <a> element.
❌ Invalid: <iframe> nested deeper inside an <a> element
<a href="https://example.com">
<div>
<iframe src="https://example.com/embed"></iframe>
</div>
</a>
Even though the <iframe> is not a direct child, it is still a descendant of the <a> element, which is not allowed.
✅ Valid: Separate the <iframe> and <a> elements
<a href="https://example.com">Visit Example.com</a>
<iframe src="https://example.com/embed"></iframe>
The link and the iframe are siblings, so there is no nesting conflict.
✅ Valid: Use an image as a clickable preview instead
If the intent is to create a clickable preview that links to a page, use a thumbnail image rather than an iframe:
<a href="https://example.com">
<img src="preview-thumbnail.jpg" alt="Preview of Example.com">
</a>
✅ Valid: Wrap in a container with a separate link
If you need both an iframe and a related link displayed together, use a wrapper element:
<div class="embed-container">
<iframe src="https://example.com/embed" title="Embedded content from Example.com"></iframe>
<p><a href="https://example.com">Open Example.com in a new page</a></p>
</div>
Note that when using <iframe>, it’s good practice to include a title attribute to describe the embedded content for accessibility purposes.
The HTML living standard defines a content model for the <a> element that explicitly excludes interactive content from appearing as descendants. Interactive content includes elements like <button>, <input>, <select>, <textarea>, and other <a> elements. When you nest an <input> inside a link, browsers face an ambiguous situation: should a click activate the link or interact with the input? Different browsers may handle this differently, leading to inconsistent behavior.
This restriction also matters for accessibility. Screen readers and other assistive technologies rely on a clear, predictable DOM structure. Nesting interactive elements creates confusion for users navigating with keyboards or screen readers, as the focus order and interaction model become unclear. A user tabbing through the page might not understand that an input lives inside a link, or they might be unable to interact with one of the two elements.
Common scenarios where this issue arises include wrapping a search input in a link to make the entire area clickable, or placing a checkbox inside a link to combine selection with navigation. In all cases, the solution is to separate the interactive elements.
Examples
❌ Incorrect: <input> inside an <a> element
<a href="/search">
<input type="text" placeholder="Search...">
</a>
This triggers the validation error because <input> is interactive content nested inside <a>.
✅ Correct: Separate the elements
<form action="/search">
<input type="text" placeholder="Search...">
<button type="submit">Search</button>
</form>
If the goal is to navigate to a search page, use a <form> with an action attribute instead of wrapping the input in a link.
❌ Incorrect: Checkbox inside a link
<a href="/settings">
<input type="checkbox" id="notify"> Enable notifications
</a>
✅ Correct: Place the link and input as siblings
<label>
<input type="checkbox" id="notify"> Enable notifications
</label>
<a href="/settings">Go to settings</a>
✅ Correct: Use styling to achieve a clickable area
If you want a visually combined area where clicking navigates somewhere, avoid using an <input> altogether and style the link instead:
<a href="/search" class="search-link">
<span>Search...</span>
</a>
Alternatively, if you need both a link and an input near each other, use CSS layout to position them visually together while keeping them as separate elements in the markup:
<div class="search-bar">
<input type="text" placeholder="Search...">
<a href="/search">Go</a>
</div>
❌ Incorrect: Hidden input inside a link
Even hidden or non-visible inputs trigger this error:
<a href="/page">
<input type="hidden" name="ref" value="home">
Click here
</a>
✅ Correct: Move the hidden input outside the link
<input type="hidden" name="ref" value="home">
<a href="/page">Click here</a>
If the hidden input is meant to pass data during navigation, consider using query parameters in the link’s href instead:
<a href="/page?ref=home">Click here</a>
The <a> element is classified as interactive content, meaning it expects user interaction (clicking to navigate). The <label> element is also interactive — clicking a label activates or focuses its associated form control. When a <label> is nested inside an <a>, the browser faces an ambiguous situation: should a click navigate to the link’s URL, or should it focus/activate the associated form control? The HTML specification resolves this by simply disallowing the nesting entirely.
According to the WHATWG HTML Living Standard, the content model of the <a> element is “transparent” but must not contain any interactive content. Since <label> is interactive content, it is not permitted as a descendant of <a> at any depth.
Beyond being invalid HTML, this nesting causes real problems:
- Accessibility: Screen readers may announce conflicting roles, confusing users who rely on assistive technology. The purpose of the element becomes unclear — is it a link or a form label?
- Unpredictable behavior: Different browsers may handle the click event differently, leading to inconsistent user experiences.
- Broken form association: The <label>‘s for attribute may not work as intended when the label is trapped inside a link.
The fix is straightforward: if you only need to style text inside a link, use a <span> or another non-interactive element instead of <label>. If you genuinely need both a link and a label, they should be separate, sibling elements rather than nested.
Examples
❌ Invalid: <label> inside <a>
<a href="/settings">
<label>Account Settings</label>
</a>
This triggers the validation error because <label> is interactive content nested inside <a>.
✅ Fixed: Replace <label> with <span>
<a href="/settings">
<span>Account Settings</span>
</a>
If the <label> was only used for styling purposes, a <span> with a CSS class achieves the same visual result without violating the specification.
❌ Invalid: <label> deeply nested inside <a>
<a href="/profile">
<div>
<label for="username">Edit Username</label>
</div>
</a>
The rule applies to all descendants, not just direct children. This is still invalid.
✅ Fixed: Separate the link and label
<label for="username">Edit Username</label>
<a href="/profile">View Profile</a>
When you need both a functional label and a link, keep them as siblings rather than nesting one inside the other.
✅ Fixed: Using <span> with a class for styling
<a href="/dashboard">
<span class="label-style">Dashboard</span>
</a>
.label-style {
font-weight: bold;
text-transform: uppercase;
}
This preserves any visual styling you need while keeping the HTML valid and the interaction model unambiguous.
The HTML specification defines <label> as an element whose content model allows phrasing content but explicitly excludes other <label> elements. When you nest one <label> inside another, browsers cannot determine which form control each label is meant to describe. This breaks the fundamental purpose of the <label> element—providing a clear, one-to-one association between a text description and its corresponding form control.
This issue matters for several reasons:
- Accessibility: Screen readers rely on the <label> element to announce the purpose of form controls. Nested labels create confusion about which label text belongs to which input, making forms difficult or impossible to navigate for users of assistive technology.
- Usability: Clicking a <label> should focus or activate its associated control. Nested labels create overlapping click targets with unpredictable behavior.
- Standards compliance: The WHATWG HTML living standard explicitly states that <label> elements must not be nested, and validators will flag this as an error.
This error commonly occurs in a few situations: accidentally duplicating closing tags, wrapping a complex form group in a <label> when a <fieldset> would be more appropriate, or using a templating system that inadvertently produces nested labels.
Examples
❌ Nested labels (invalid)
<label>
Full Name
<label>
First Name
<input type="text" name="first-name">
</label>
</label>
❌ Extra closing tag causing a parser issue
A stray closing </label> tag can sometimes cause the browser’s error recovery to produce unexpected nesting:
<label>Name</label></label>
<label for="email">Email</label>
While the extra </label> is the root problem here, some parsers and validators may interpret this as a nesting issue. Always ensure your opening and closing tags are properly matched.
✅ Separate labels for separate inputs
<label for="first-name">First Name</label>
<input type="text" id="first-name" name="first-name">
<label for="last-name">Last Name</label>
<input type="text" id="last-name" name="last-name">
✅ Using implicit label association (one label per input)
<label>
First Name
<input type="text" name="first-name">
</label>
<label>
Last Name
<input type="text" name="last-name">
</label>
✅ Grouping related controls with <fieldset> instead of nesting labels
If you need to group multiple labeled inputs under a shared heading, use a <fieldset> with a <legend> instead of wrapping labels inside a label:
<fieldset>
<legend>Full Name</legend>
<label for="first-name">First Name</label>
<input type="text" id="first-name" name="first-name">
<label for="last-name">Last Name</label>
<input type="text" id="last-name" name="last-name">
</fieldset>
This approach provides the grouping semantics you need while keeping each <label> correctly associated with a single form control. The <legend> serves as the group-level description, and each <label> describes its individual input—giving both sighted users and assistive technology users a clear understanding of the form structure.
The <caption> element is designed to be a brief, descriptive label for its parent <table>. According to the HTML specification, <caption> accepts flow content but explicitly forbids descendant <table> elements. This restriction exists because a table nested inside a caption creates a confusing and semantically meaningless structure — the caption is supposed to describe the table, not contain another one.
Why this is a problem
- Accessibility: Screen readers announce the <caption> as the title of the table. A nested table inside a caption creates a confusing experience for assistive technology users, as the relationship between the tables becomes ambiguous and the caption loses its descriptive purpose.
- Standards compliance: The WHATWG HTML living standard explicitly states that <caption> must have “no <table> element descendants.” Violating this produces a validation error.
- Rendering inconsistencies: Browsers may handle this invalid nesting differently, leading to broken or unpredictable layouts across different environments.
How to fix it
- Remove the table from the caption. The <caption> should contain only text and simple inline elements like <span>, <strong>, <em>, or <a>.
- Place the nested table outside the parent table, either before or after it, or restructure your layout so both tables are siblings.
- If the data in the nested table is genuinely related to the caption’s purpose, consider expressing it as plain text or using a different structural approach entirely.
Examples
❌ Incorrect: A table nested inside a caption
<table>
<caption>
Summary
<table>
<tr>
<td>Extra info</td>
<td>Details</td>
</tr>
</table>
</caption>
<tr>
<th>Name</th>
<th>Score</th>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
This triggers the validation error because a <table> appears as a descendant of the <caption> element.
✅ Correct: Caption contains only text, tables are separate
<table>
<caption>Summary — Extra info: Details</caption>
<tr>
<th>Name</th>
<th>Score</th>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
If the extra information truly requires its own table, place it as a sibling:
<table>
<caption>Summary</caption>
<tr>
<th>Name</th>
<th>Score</th>
</tr>
<tr>
<td>Alice</td>
<td>95</td>
</tr>
</table>
<table>
<caption>Additional details</caption>
<tr>
<td>Extra info</td>
<td>Details</td>
</tr>
</table>
✅ Correct: Caption with inline formatting only
<table>
<caption>
<strong>Quarterly Results</strong> — <em>All figures in USD</em>
</caption>
<tr>
<th>Quarter</th>
<th>Revenue</th>
</tr>
<tr>
<td>Q1</td>
<td>$1.2M</td>
</tr>
</table>
This is valid because the <caption> contains only text and inline elements (<strong>, <em>), with no <table> descendants.
The <a> element is classified as interactive content, and the HTML spec explicitly states that interactive content must not be nested inside other interactive content. A <textarea> is a form control that accepts user input—clicking, focusing, typing, and selecting text within it. When it’s wrapped in a link, the browser faces a conflict: should a click focus the textarea or follow the link? Different browsers may resolve this differently, leading to inconsistent behavior.
Beyond browser inconsistency, this nesting creates serious accessibility problems. Screen readers and other assistive technologies rely on a clear, predictable document structure. When a form control is buried inside a link, the roles and interaction models overlap, making it confusing or even impossible for users relying on keyboard navigation or screen readers to interact with either element properly.
The fix depends on what you’re trying to achieve. If the <textarea> and the link are logically separate, simply move them to be siblings rather than nesting one inside the other. If you need them to appear visually grouped, use a wrapper <div> or another non-interactive container element instead.
Examples
❌ Invalid: <textarea> inside an <a> element
<a href="/comments">
<textarea name="comment" rows="4" cols="40"></textarea>
</a>
This triggers the validation error because the <textarea> is a descendant of the <a> element.
✅ Valid: <textarea> and <a> as siblings
<div>
<textarea name="comment" rows="4" cols="40"></textarea>
<a href="/comments">View all comments</a>
</div>
Here, both elements live side by side inside a neutral <div>, avoiding any nesting conflict.
✅ Valid: <textarea> inside a <form> with a separate link
<form action="/submit-comment" method="post">
<label for="comment">Your comment:</label>
<textarea id="comment" name="comment" rows="4" cols="40"></textarea>
<button type="submit">Submit</button>
</form>
<a href="/comments">View all comments</a>
This is the most semantically correct approach when the textarea is part of a form—keep the form controls in a <form> and place any navigation links outside of it.
Other interactive elements to watch for
The same rule applies to other interactive content inside <a> elements. You also cannot nest <button>, <input>, <select>, <details>, or another <a> inside a link. If the validator reports a similar error for any of these elements, the fix follows the same principle: move the interactive element out of the anchor.
Ready to validate your sites?
Start your free trial today.