HTML Guides
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.
Required attributes exist because they provide information that is fundamental to the element's purpose. For example, an <img> element without a src attribute has no image to display, and without an alt attribute, assistive technologies have no fallback text to describe the image. A <link> element without rel gives the browser no way to understand the relationship of the linked resource. When you omit a required attribute, several things can go wrong:
- Accessibility issues: Screen readers and other assistive technologies depend on specific attributes to convey meaning. A missing
alton<img>leaves visually impaired users without any description of the content. - Broken functionality: Some elements simply won't work without their required attributes. A
<form>with an<input>that's missing atypeattribute may still render (browsers default totype="text"), but other elements like<map>withoutnamewon't function as intended. - Standards non-compliance: Omitting required attributes produces invalid HTML, which can lead to unpredictable rendering across different browsers.
To fix this issue, identify which attribute is missing from the element flagged by the validator, then add it with an appropriate value. Here are common elements and their required attributes:
| Element | Required Attribute(s) |
|---|---|
<img> | src, alt |
<link> | rel |
<script> | src (if no inline content) |
<input> | type (recommended) |
<meta> | charset, name, or http-equiv (at least one) |
<map> | name |
<bdo> | dir |
<style> | None in HTML5, but type was required in HTML4 |
Examples
Missing alt attribute on <img>
This is one of the most common validation errors. The alt attribute is required on every <img> element.
❌ Incorrect — missing alt attribute:
<img src="photo.jpg">
✅ Correct — alt attribute provided:
<img src="photo.jpg" alt="A sunset over the ocean">
If the image is purely decorative and carries no meaningful content, use an empty alt attribute:
<img src="decorative-border.png" alt="">
Missing rel attribute on <link>
The rel attribute tells the browser what the linked resource is for.
❌ Incorrect — missing rel attribute:
<link href="styles.css">
✅ Correct — rel attribute provided:
<link rel="stylesheet" href="styles.css">
Missing name attribute on <map>
The <map> element requires a name attribute so it can be referenced by an <img> element's usemap attribute.
❌ Incorrect — missing name attribute:
<map>
<area shape="rect" coords="0,0,100,100" href="/section" alt="Section">
</map>
✅ Correct — name attribute provided:
<map name="navigation">
<area shape="rect" coords="0,0,100,100" href="/section" alt="Section">
</map>
<img src="nav.png" alt="Site navigation" usemap="#navigation">
Missing dir attribute on <bdo>
The <bdo> (bidirectional override) element exists specifically to override text direction, so the dir attribute is essential.
❌ Incorrect — missing dir attribute:
<p>The word in Arabic is <bdo>مرحبا</bdo>.</p>
✅ Correct — dir attribute provided:
<p>The word in Arabic is <bdo dir="rtl">مرحبا</bdo>.</p>
When you encounter this validation error, read the validator message carefully — it will tell you exactly which element and which attribute is missing. Add the attribute with a meaningful value appropriate to your content, and revalidate to confirm the issue is resolved.
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>
Headings play a critical role in structuring a web page. They create an outline of the document that both users and machines rely on. Screen readers, for example, allow users to navigate a page by jumping between headings, making them one of the most important tools for accessible navigation. When a heading is empty, screen readers may announce "heading level 2" (or similar) with no accompanying text, leaving users confused about what section they've entered.
Empty headings also signal a structural problem. They often appear when developers use heading elements purely for spacing or styling purposes, when content is meant to be injected dynamically via JavaScript but the script fails, or when headings are left as placeholders during development and never filled in.
The W3C validator flags this as a warning because the HTML specification states that headings represent the topic of their section. An empty heading cannot fulfill this purpose. While it is technically parseable HTML, it is semantically meaningless and degrades the quality of the document.
How to fix it
- Add descriptive text to the heading that accurately represents the content of its section.
- Remove the empty heading if it serves no purpose. Don't keep empty headings as spacers — use CSS margins or padding instead.
- If content is loaded dynamically, consider adding the heading element via JavaScript at the same time as its content, rather than leaving an empty shell in the markup.
- If you're hiding the heading visually but still want it available for screen readers, use a visually-hidden CSS technique rather than leaving it empty.
Examples
❌ Empty headings (triggers the warning)
<h1></h1>
<h2> </h2>
<h3>
</h3>
All three of these are considered empty — even the ones containing whitespace or a newline.
❌ Using an empty heading for spacing
<h2></h2>
<p>This paragraph needs some space above it.</p>
This misuses a heading element for visual layout purposes.
✅ Heading with meaningful content
<h1>Welcome to Our Store</h1>
<h2>Featured Products</h2>
<p>Check out our latest arrivals.</p>
✅ Using CSS for spacing instead of empty headings
<p class="section-intro">This paragraph needs some space above it.</p>
.section-intro {
margin-top: 2rem;
}
✅ Visually hidden heading for screen readers
If you need a heading that is available to assistive technologies but not visible on screen, include text and hide it with CSS:
<h2 class="visually-hidden">Navigation Menu</h2>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
✅ Adding headings dynamically with their content
Instead of placing an empty heading in the HTML and populating it later, create the heading along with its content:
<div id="results"></div>
<script>
const container = document.getElementById("results");
const heading = document.createElement("h2");
heading.textContent = "Search Results";
container.appendChild(heading);
</script>
This approach avoids any moment where an empty heading exists in the DOM, ensuring validity and accessibility at all times.
When the browser's HTML parser reaches the end of the file, it expects all opened elements to have been closed. If they haven't, the validator flags each unclosed element individually. While browsers will attempt to auto-close these elements using error recovery rules, the results can be unpredictable — different browsers may interpret the intended structure differently, leading to inconsistent rendering, broken layouts, and unexpected behavior.
This error is especially problematic for accessibility. Screen readers and other assistive technologies rely on a well-formed document tree to convey page structure to users. Unclosed elements can create a malformed DOM where content ends up nested inside the wrong parent, making navigation confusing or impossible for people using assistive devices.
There are several common causes for this error:
- Missing closing tags — Forgetting to write
</div>,</section>,</p>, or similar end tags. - Missing
</body>or</html>— The document's outermost structural tags are left unclosed, often because the bottom of the file was truncated or accidentally deleted. - Mismatched nesting — Closing tags appear in the wrong order, which can cause the parser to treat elements as still open. For example,
<b><i></b></i>closes<b>before<i>, leaving<i>effectively unclosed from the parser's perspective. - Typos in closing tags — Writing
</dev>instead of</div>, which the parser doesn't recognize as a valid closing tag for the open element. - Template or build errors — Server-side templates, component frameworks, or build tools sometimes produce partial HTML output that is missing closing tags.
To fix this issue, work through your document methodically. Use your code editor's bracket matching or tag highlighting features to pair each start tag with its end tag. Proper indentation makes this much easier — when nested elements are consistently indented, a missing closing tag becomes visually obvious because the indentation levels won't line up.
Examples
Missing closing tags throughout the document
This document has multiple unclosed elements, including the structural <footer>, <body>, and <html> tags:
<!-- ❌ Triggers the error -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample Page</title>
</head>
<body>
<div>
<h1>Welcome to My Page
<p>This is a paragraph in a div.
</div>
<footer>
<p>Footer content here
The validator will report open elements for <h1>, the <p> tags, <footer>, <body>, and <html>. Here is the corrected version:
<!-- ✅ All elements properly closed -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Sample Page</title>
</head>
<body>
<div>
<h1>Welcome to My Page</h1>
<p>This is a paragraph in a div.</p>
</div>
<footer>
<p>Footer content here</p>
</footer>
</body>
</html>
Mismatched nesting order
Even when all closing tags are technically present, the wrong order can trigger this error:
<!-- ❌ Tags closed in the wrong order -->
<div>
<section>
<p>Some content</p>
</div>
</section>
The </div> appears before </section>, but <section> is nested inside <div>. The parser closes <div> first, and because <section> was opened inside it, the explicit </section> that follows doesn't match anything correctly. Fix this by closing elements in reverse order of how they were opened:
<!-- ✅ Correct nesting order -->
<div>
<section>
<p>Some content</p>
</section>
</div>
Typo in a closing tag
A subtle typo can leave an element open without any obvious visual clue:
<!-- ❌ Typo: </setion> instead of </section> -->
<section>
<p>Article content</p>
</setion>
The parser doesn't recognize </setion> as the closing tag for <section>, so <section> remains open. Correct the spelling:
<!-- ✅ Properly spelled closing tag -->
<section>
<p>Article content</p>
</section>
Void elements mistakenly given closing tags that disrupt nesting
Sometimes adding a closing tag to a void element like <input> or <br> can confuse the parser and cause downstream nesting issues. Void elements must not have closing tags:
<!-- ❌ Closing tag on a void element can cause confusion -->
<div>
<input type="text"></input>
</div>
<!-- ✅ Void elements are self-closing; no end tag needed -->
<div>
<input type="text">
</div>
Tips for preventing this issue
- Indent consistently — Use two or four spaces for each nesting level. When every child element is indented one level deeper than its parent, missing closing tags become easy to spot.
- Use editor features — Most code editors offer tag auto-closing, bracket matching, and tag pair highlighting. Enable these to catch mistakes as you type.
- Validate early and often — Run your HTML through the W3C validator during development, not just at the end. This catches unclosed elements before they cascade into dozens of related errors.
- Check complex structures carefully — Tables, forms, nested lists, and multi-level layouts have many nested elements. These are the most common places where a closing tag gets accidentally omitted or misplaced.
- Review template output — If you use server-side templates or a JavaScript framework that generates HTML, validate the rendered output, not just the source template. Conditional logic in templates is a frequent source of missing closing tags.
An HTML element was opened but never closed before the document ended, meaning the parser reached the end of the file while still expecting content or a closing tag.
This error occurs when there is a mismatch between opening and closing tags in your document. Common causes include a missing closing tag (like </div>, </body>, or </html>), an extra opening tag, or accidentally deleted lines. The HTML parser keeps track of every element it opens, and when it reaches the end of the file with unclosed elements still on its stack, it reports this error.
The best way to track this down is to check that every opening tag has a corresponding closing tag, paying special attention to deeply nested structures. Look for missing </div>, </section>, </main>, </body>, or </html> tags — these are the most frequently forgotten.
HTML Examples
❌ Broken: missing closing tags
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<div class="wrapper">
<main>
<p>Hello world</p>
</main>
In this example, the </div>, </body>, and </html> closing tags are all missing. The parser reaches the end of the file while still expecting them.
✅ Fixed: all tags properly closed
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<div class="wrapper">
<main>
<p>Hello world</p>
</main>
</div>
</body>
</html>
A good habit is to write both the opening and closing tags at the same time, then fill in the content between them. Most code editors also offer auto-closing and bracket-matching features that help prevent this issue.
Every HTML document must begin with a Document Type Declaration (doctype). The doctype tells browsers which version and standard of HTML the document uses, ensuring they render the page in standards mode rather than quirks mode. Without it, browsers fall back to quirks mode, which emulates legacy rendering behavior from the early web — leading to inconsistent layouts, unexpected CSS behavior, and subtle bugs that differ across browsers.
Since HTML5, the doctype is simply <!DOCTYPE html>. It is case-insensitive (<!doctype html> also works), but it must appear before any other content in the document, including the <html> tag. Even a blank line or whitespace before the doctype can sometimes cause issues in older browsers.
This error can be triggered by several common scenarios:
- The doctype is completely missing. The file jumps straight into
<html>or other markup. - The doctype is misspelled. For example,
<!DOCKTYPE html>or<!DOCTYPE hmtl>. - The file is empty or contains only non-HTML content. The validator reached the end without finding any valid HTML structure.
- A Byte Order Mark (BOM) or invisible characters appear before the doctype, which can happen when files are saved with certain text editors.
- The doctype is placed after other elements, such as a comment or
<html>tag.
To fix this, ensure <!DOCTYPE html> is the very first line of your file, with no preceding content.
Examples
❌ Missing doctype entirely
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
This triggers the error because the validator never encounters a doctype declaration.
❌ Misspelled doctype
<!DOCKTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The typo DOCKTYPE means the validator does not recognize it as a valid doctype.
❌ Doctype placed after the <html> tag
<html lang="en">
<!DOCTYPE html>
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The doctype must come before the <html> tag, not after it.
✅ Correct minimal HTML5 document
<!DOCTYPE html>
<html lang="en">
<head>
<title>My Page</title>
</head>
<body>
<p>Hello, world!</p>
</body>
</html>
The <!DOCTYPE html> declaration appears on the very first line, followed by the <html> tag with a lang attribute, a <head> containing a <title>, and a <body> with the page content. This is the minimal structure for a valid HTML5 document.
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.
In HTML, certain elements are classified as void elements — they cannot contain any content and must not have a closing (end) tag. The <br> element, which represents a line break, is one of these void elements. Others include <img>, <input>, <hr>, <meta>, and <link>.
When the validator encounters </br>, it interprets it as a closing tag for a <br> element. Since void elements are forbidden from having closing tags by the HTML specification, this produces the error "End tag br."
Why this matters
- Standards compliance: The WHATWG HTML Living Standard explicitly states that void elements must not have an end tag. Using
</br>violates this rule. - Browser inconsistency: While most browsers will silently recover from
</br>— some treat it as a<br>, others may ignore it entirely — relying on error recovery behavior is unpredictable and can lead to inconsistent rendering across browsers. - Code clarity: Using
</br>suggests the element has an opening and closing pair, which is misleading to other developers reading the code. It implies a misunderstanding of how the element works.
How to fix it
Replace every instance of </br> with <br>. That's it. There's no need for a closing tag because <br> is self-closing by definition.
Both <br> and <br/> (with a trailing slash) are valid in HTML5. The <br> form is generally preferred in HTML documents, while <br/> is required in XHTML and sometimes used for compatibility with XML-based tools.
Examples
❌ Invalid: using an end tag for <br>
<p>First line</br>Second line</p>
This triggers the "End tag br" validation error.
❌ Also invalid: pairing an opening and closing <br> tag
<p>First line<br></br>Second line</p>
Even when paired with an opening <br>, the </br> end tag is still invalid.
✅ Valid: using <br> without a closing tag
<p>First line<br>Second line</p>
✅ Also valid: self-closing syntax with a trailing slash
<p>First line<br/>Second line</p>
This form is acceptable in HTML5, though <br> without the slash is more conventional in modern HTML.
✅ Practical example: an address block
<address>
123 Main Street<br>
Suite 400<br>
Springfield, IL 62704
</address>
Other void elements
The same rule applies to all void elements. None of these should have closing tags:
<area>, <base>, <br>, <col>, <embed>, <hr>, <img>, <input>, <link>, <meta>, <source>, <track>, <wbr>
If you see a similar "End tag" error for any of these elements, the fix is the same: remove the closing tag.
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.
The closing </font> tag closes across the boundary of another element that was still open. Tags have to nest cleanly: the element you opened last is the one you close first. When </font> appears while something opened inside it is still open, or it reaches past the element that contains it, the parser can't build a sensible tree and falls back to the adoption agency algorithm to patch things up. Different browsers can patch them differently, so the DOM you get may not match the DOM you wrote, and screen readers lose the real structure of the content.
Examples
Incorrect: </font> crosses a <p> boundary
<p><font color="red">Some text</p>
<p>More text</font></p>
The <font> opens in the first paragraph but closes in the second, so the tags overlap.
Correct: each <font> opens and closes in the same element
<p><font color="red">Some text</font></p>
<p><font color="red">More text</font></p>
Incorrect: closed before a nested <a>
<p><font color="red"><a href="/about">About us</font></a></p>
The <a> opened inside the <font>, so </a> has to come before </font>.
Correct: inner element closed first
<p><font color="red"><a href="/about">About us</a></font></p>
<font> is also obsolete
Fixing the nesting still leaves you with a <font> element, which was dropped from HTML5. Browsers keep parsing it, but the validator flags it on its own too. The simplest fix for both problems is to drop <font> and style the text with CSS. A <span> nests far more predictably:
<style>
.highlight {
color: red;
font-size: 1.2em;
}
</style>
<p>
<span class="highlight">This text is styled with CSS.</span>
</p>
Swapping <font> for CSS properties like color, font-size, and font-family clears the nesting violation and the obsolete-element warning at the same time.
When the browser encounters a </body> tag while elements like <div>, <section>, <p>, or <span> are still open, it must guess where those elements were supposed to end. Different browsers may guess differently, leading to inconsistent rendering and a DOM structure that doesn't match your intent. This can cause layout problems, broken styling, and accessibility issues — screen readers rely on a well-formed DOM to convey the correct document structure to users.
The root causes of this error typically include:
- Forgetting a closing tag — the most common scenario, especially with deeply nested structures.
- Mismatched tags — closing tags that don't correspond to their opening tags (e.g., opening a
<div>but closing it with</section>). - Copy-paste errors — duplicating or deleting code that leaves behind orphaned opening tags.
- Incorrect nesting — overlapping elements where tags cross boundaries instead of being properly nested.
To fix the issue, work through the validator's error list from top to bottom. The error message usually identifies which elements are unclosed. Find each one and either add the missing closing tag in the correct position or remove the unnecessary opening tag. Using consistent indentation makes it much easier to spot mismatches visually.
Examples
Missing closing tag
This triggers the error because the <section> element is never closed:
<body>
<section>
<h1>Welcome</h1>
<p>Hello, world!</p>
</body>
Add the missing </section> closing tag:
<body>
<section>
<h1>Welcome</h1>
<p>Hello, world!</p>
</section>
</body>
Multiple unclosed elements
Here, both the <div> and the <ul> are left open:
<body>
<div class="sidebar">
<ul>
<li>Home</li>
<li>About</li>
</body>
Close each element in the correct (reverse) order:
<body>
<div class="sidebar">
<ul>
<li>Home</li>
<li>About</li>
</ul>
</div>
</body>
Mismatched closing tag
A mismatch between opening and closing tags can also produce this error. The <div> is opened but </section> is used to close it, leaving the <div> unclosed:
<body>
<div class="content">
<p>Some text here.</p>
</section>
</body>
Fix the closing tag so it matches the opening tag:
<body>
<div class="content">
<p>Some text here.</p>
</div>
</body>
Overlapping (improperly nested) elements
Elements that overlap instead of nesting properly will also trigger this error. Here the <b> and <i> tags cross each other's boundaries:
<body>
<p><b>Bold and <i>italic</b> text</i></p>
</body>
Ensure elements are closed in the reverse order they were opened:
<body>
<p><b>Bold and <i>italic</i></b><i> text</i></p>
</body>
The HTML specification is clear on this point: an end tag consists solely of </, the tag name, optional whitespace, and >. No attributes, no values, no extra content of any kind is permitted. This rule applies universally to every HTML element.
This error usually occurs due to one of a few common mistakes:
- Misplaced attributes: An attribute like
classoridwas accidentally typed on the closing tag instead of (or in addition to) the opening tag. - Copy-paste errors: When duplicating or restructuring code, attributes may end up attached to the wrong tag.
- Typos or malformed tags: A missing
>on the opening tag can cause the browser or validator to interpret what follows as part of the end tag.
While most browsers are forgiving and will simply ignore attributes on closing tags, this is still a problem. It signals malformed markup that can cause unpredictable behavior in parsers, screen readers, and other tools that process HTML. It also makes your code harder to read and maintain, and it may indicate a deeper structural issue — such as an attribute that was meant to be on the opening tag and is therefore not being applied at all.
Examples
Attribute accidentally placed on the closing tag
This triggers the error because class appears on the </p> end tag:
<p>Welcome to the site.</p class="welcome">
Remove the attribute from the closing tag and place it on the opening tag:
<p class="welcome">Welcome to the site.</p>
Attribute duplicated on both tags
Sometimes attributes appear on both the opening and closing tags:
<div id="sidebar" class="panel">
<p>Sidebar content</p>
</div id="sidebar">
The fix is to remove all attributes from the closing tag:
<div id="sidebar" class="panel">
<p>Sidebar content</p>
</div>
Missing > on the opening tag causing a cascade
A subtle typo on the opening tag can lead to this error. Here, the missing > after the opening <h2 causes the validator to misinterpret the markup:
<h2 class="title"Chapter One</h2>
Adding the missing > fixes the structure:
<h2 class="title">Chapter One</h2>
Multiple elements with the same mistake
This pattern sometimes appears when developers add attributes to closing tags as informal "comments" to track which element is being closed:
<div class="header">
<nav class="main-nav">
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav class="main-nav">
</div class="header">
If you want to annotate closing tags for readability, use HTML comments instead:
<div class="header">
<nav class="main-nav">
<ul>
<li><a href="/">Home</a></li>
</ul>
</nav><!-- .main-nav -->
</div><!-- .header -->
HTML follows a strict stack-based nesting model. When you open an element, it becomes the "current" element, and any new element you open becomes a child of it. Closing tags must mirror the opening order in reverse. When the validator encounters </i> but the most recently opened unclosed element is something else — like <strong>, <b>, <span>, or <a> — the nesting rules are violated because the <i> element and the other element are overlapping rather than containing one another.
For example, if you write <i>...<strong>...</i>...</strong>, the <i> and <strong> elements overlap. The <i> tries to close while <strong> is still open inside it, and then <strong> tries to close outside of <i>. This creates an ambiguous structure that no valid DOM tree can represent as written. Browsers will attempt to "fix" this using error-recovery algorithms, but the result may differ across browsers and is unlikely to match your intent.
Why this matters
- Unpredictable rendering: Browser error-recovery can silently restructure your markup, leading to missing styles, broken links, or misplaced text.
- Accessibility: Screen readers rely on a well-formed DOM tree. Mis-nested elements can cause assistive technology to misinterpret the structure, reading content out of order or missing emphasis cues entirely.
- Maintainability: Overlapping tags make code harder to read and debug. Future edits are more likely to introduce additional errors.
Common causes
- Overlapping inline elements: Opening
<i>and then<b>(or<strong>,<em>,<span>, etc.) but closing</i>before</b>. - Tags crossing an anchor boundary: Starting
<i>outside an<a>element but closing it inside, or vice versa. - Copy-paste errors: Duplicating a block of HTML that includes icons (e.g., Font Awesome
<i>tags) or screen-reader-only<span>elements, then editing part of it without fixing the tag order. - Mixing presentational and semantic markup: Wrapping
<i>around content that already contains<em>or<strong>, then accidentally closing in the wrong sequence.
How to fix it
- Identify the overlapping pair. The validator message usually points to the line where
</i>appears. Look for the nearest unclosed element that was opened after<i>. - Reorder the closing tags so they mirror the opening order in reverse. If you opened
<i>then<strong>, close</strong>then</i>. - If the overlap is intentional (e.g., you want bold-italic text that transitions to just bold), restructure by closing and reopening elements at the boundary rather than overlapping them.
- Consider semantic alternatives. The
<i>element is for idiomatic text (technical terms, foreign phrases, thoughts). If you need emphasis, use<em>. If you only need italic styling, use CSSfont-style: italic;. Whichever element you choose, the nesting rules are the same.
Examples
Incorrect — overlapping <i> and <strong>
The </i> closes while <strong> is still open inside it:
<p>
<a href="/about"><i>About <strong>Us</i></strong></a>
</p>
Correct — properly nested
Close <strong> first, then <i>:
<p>
<a href="/about"><i>About <strong>Us</strong></i></a>
</p>
Incorrect — <i> crossing an anchor boundary
<p>
<i><a href="/contact">Contact us</i></a> for more info.
</p>
Correct — keep <i> fully inside or fully outside the link
<p>
<a href="/contact"><i>Contact us</i></a> for more info.
</p>
Incorrect — overlapping inline elements with a style transition
Trying to make "bold italic" transition to "just bold" by overlapping:
<p>
<i>Italic and <b>bold-italic</i> then just bold.</b>
</p>
Correct — close and reopen at the boundary
<p>
<i>Italic and <b>bold-italic</b></i><b> then just bold.</b>
</p>
Incorrect — icon element mis-nested with a span
<button>
<i class="icon-search"><span class="sr-only">Search</i></span>
</button>
Correct — close <span> before <i>
<button>
<i class="icon-search"><span class="sr-only">Search</span></i>
</button>
A quick way to check your nesting is to read through your opening tags in order and then confirm the closing tags appear in exactly the reverse order. If you opened <a>, <i>, <strong>, the closing sequence must be </strong>, </i>, </a>. When in doubt, use your editor's bracket-matching or tag-highlighting feature to visually trace each pair.
When the HTML parser reaches a </li> closing tag, it expects all elements nested within that list item to already be closed. If any child element remains open, the browser must guess where to close it, which can lead to an unexpected DOM structure. This error typically occurs when a closing tag is accidentally omitted, misspelled, or placed in the wrong order.
This matters for several reasons. First, browsers may interpret the intended structure differently, causing inconsistent rendering across platforms. Second, assistive technologies like screen readers rely on a well-formed DOM to convey content correctly — unclosed elements can confuse the reading order or grouping of content. Third, unclosed elements can cascade into other validation errors, making it harder to identify the real problems in your markup.
Common causes of this error include:
- Forgetting to close an inline element like
<span>,<a>,<strong>, or<em>inside a list item. - Forgetting to close a block-level element like
<div>or<p>inside a list item. - Nesting elements in the wrong order, so closing tags don't match their opening tags.
- Typos in closing tags (e.g.,
</sapn>instead of</span>).
To fix the issue, locate the <li> mentioned in the error and check every element opened inside it. Make sure each one has a corresponding, correctly spelled closing tag, and that they are closed in the reverse order they were opened (last opened, first closed).
Examples
Missing closing tag on an inline element
❌ Invalid: The <span> is never closed before </li>.
<ul>
<li>
<span>Example text
</li>
</ul>
✅ Valid: The <span> is properly closed.
<ul>
<li>
<span>Example text</span>
</li>
</ul>
Missing closing tag on a link
❌ Invalid: The <a> element is left open.
<ul>
<li>
<a href="/about">About us
</li>
<li>
<a href="/contact">Contact</a>
</li>
</ul>
✅ Valid: Both <a> elements are closed before their parent </li>.
<ul>
<li>
<a href="/about">About us</a>
</li>
<li>
<a href="/contact">Contact</a>
</li>
</ul>
Multiple unclosed nested elements
❌ Invalid: Both <strong> and <a> are left open inside the <li>.
<ol>
<li>
<a href="/sale"><strong>Big sale
</li>
</ol>
✅ Valid: Nested elements are closed in reverse order (innermost first).
<ol>
<li>
<a href="/sale"><strong>Big sale</strong></a>
</li>
</ol>
Misspelled closing tag
❌ Invalid: The closing tag </sapn> doesn't match <span>, so the <span> remains open.
<ul>
<li>
<span>Item one</sapn>
</li>
</ul>
✅ Valid: The closing tag is spelled correctly.
<ul>
<li>
<span>Item one</span>
</li>
</ul>
Incorrectly ordered closing tags
❌ Invalid: The </em> and </strong> tags are closed in the wrong order, leaving <em> effectively unclosed when </strong> is reached.
<ul>
<li>
<strong><em>Important note</strong></em>
</li>
</ul>
✅ Valid: Closing tags are in the correct reverse order.
<ul>
<li>
<strong><em>Important note</em></strong>
</li>
</ul>
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.
HTML follows strict nesting rules: elements must be closed in the reverse order they were opened, like a stack. When the validator encounters </X> but the current open element is Y, it means something has gone wrong in the document structure. The browser's parser will attempt to recover from this mismatch, but the result may not reflect your intended layout or semantics.
There are several common causes for this error:
- Typos in tag names — for example, opening a
<div>but closing it with</dvi>. - Mismatched tags — opening one element but closing a different one, such as
<strong>closed with</em>. - Incorrect nesting order — overlapping elements where tags cross boundaries instead of being properly nested.
- Missing closing tags — a forgotten closing tag causes subsequent closing tags to be misaligned with the parser's expectation.
This matters because improperly nested HTML can cause unpredictable rendering across browsers, break CSS styling, interfere with JavaScript DOM manipulation, and create accessibility problems for screen readers that rely on a well-formed document tree.
To fix this error, trace back from the reported line to find where the mismatch originates. Ensure that every opening tag has a corresponding closing tag with the exact same name, and that elements are closed in the correct order (last opened, first closed).
Examples
Typo in the closing tag
<!-- ❌ Wrong: closing tag is misspelled -->
<section>
<p>Hello world</p>
</secton>
<!-- ✅ Fixed: closing tag matches the opening tag -->
<section>
<p>Hello world</p>
</section>
Mismatched tags
<!-- ❌ Wrong: <strong> is closed with </em> -->
<p>This is <strong>important</em> text.</p>
<!-- ✅ Fixed: closing tag matches the opening tag -->
<p>This is <strong>important</strong> text.</p>
Incorrectly nested (overlapping) elements
<!-- ❌ Wrong: <b> and <i> overlap each other -->
<p><b>Bold <i>and italic</b> text</i></p>
The validator sees </b> when the current open element is <i>. Elements must nest completely inside one another without overlapping.
<!-- ✅ Fixed: elements are properly nested -->
<p><b>Bold <i>and italic</i></b><i> text</i></p>
Missing closing tag causing a cascade of errors
<!-- ❌ Wrong: missing </div> for the inner div -->
<div class="outer">
<div class="inner">
<p>Content</p>
</div>
Here the single </div> closes inner, leaving outer unclosed. If more HTML follows, subsequent closing tags will be misaligned, potentially producing this error further down in the document.
<!-- ✅ Fixed: both divs are properly closed -->
<div class="outer">
<div class="inner">
<p>Content</p>
</div>
</div>
Tips for debugging
- Work from the first error — in HTML validation, one early mistake can cascade into many subsequent errors. Fix the first reported mismatch and re-validate before tackling later errors.
- Use consistent indentation — properly indented code makes it much easier to spot where nesting goes wrong.
- Use an editor with bracket/tag matching — most code editors can highlight matching opening and closing tags, making mismatches immediately visible.
The HTML specification defines strict rules about how elements must be nested and closed. When the parser reaches a point where it needs to close a parent element — either because it encounters the parent's explicit end tag or because a sibling element implicitly closes it — any child elements that are still open create a problem. The browser's error-recovery mechanism will attempt to auto-close those elements, but the result may not match your intent, leading to unexpected DOM structures, broken layouts, or accessibility issues.
This error is especially common with <li>, <p>, and <td> elements because their end tags are optional in HTML. When the parser sees a new <li> while a previous <li> is still open, it implicitly closes the first one. If there are unclosed child elements inside that first <li>, you'll get this warning.
There are several common scenarios that trigger this issue:
- Forgetting to close an inline element (like
<span>,<a>, or<strong>) inside a list item, table cell, or paragraph. - Mismatched or misordered closing tags where elements overlap instead of nesting properly.
- Accidentally omitting a closing tag in a deeply nested structure.
Beyond validation, unclosed elements can cause real problems. Screen readers may misinterpret the document structure, CSS selectors may not match as expected, and browsers may construct a DOM tree that differs from what you intended. Fixing these issues ensures consistent rendering across browsers and a reliable experience for all users.
How to Fix
- Locate the open element mentioned in the error. The validator usually tells you which element is still open.
- Add the missing closing tag in the correct position — before the parent element's end tag or before the next sibling that would implicitly close the parent.
- Verify proper nesting order. Elements must be closed in the reverse order they were opened (last opened, first closed).
Examples
Unclosed <span> inside a list item
The <span> is never closed, so when the parser encounters the second <li>, it implicitly closes the first <li> while <span> is still open:
<!-- ❌ Triggers: End tag "li" implied, but there were open elements -->
<ul>
<li><span>First item</li>
<li>Second item</li>
</ul>
Close the <span> before the <li> ends:
<!-- ✅ Correct -->
<ul>
<li><span>First item</span></li>
<li>Second item</li>
</ul>
Implicit <li> closure with open child element
When a new <li> appears, the previous <li> is auto-closed. If a <strong> tag is still open inside it, this error is raised:
<!-- ❌ Triggers the error -->
<ul>
<li><strong>Important text<li>Other item</li>
</ul>
<!-- ✅ Correct -->
<ul>
<li><strong>Important text</strong></li>
<li>Other item</li>
</ul>
Unclosed <a> inside a <p> before a block element
When the parser encounters a <div> (or another block element), it implicitly closes the <p>, leaving the <a> unclosed:
<!-- ❌ Triggers the error -->
<p>Visit <a href="/about">our page
<div>Other content</div>
<!-- ✅ Correct -->
<p>Visit <a href="/about">our page</a></p>
<div>Other content</div>
Misordered closing tags
Closing tags must appear in reverse order of their opening tags. Overlapping elements are invalid:
<!-- ❌ Triggers the error -->
<p><em><strong>Bold italic text</em></strong></p>
<!-- ✅ Correct: close in reverse order -->
<p><em><strong>Bold italic text</strong></em></p>
Unclosed element in a table cell
<!-- ❌ Triggers the error -->
<table>
<tr>
<td><span>Data</td>
<td>More data</td>
</tr>
</table>
<!-- ✅ Correct -->
<table>
<tr>
<td><span>Data</span></td>
<td>More data</td>
</tr>
</table>
When you see this error, look for the unclosed element the validator identifies, add its closing tag in the correct position, and make sure all elements follow proper nesting order. If multiple instances of this error appear in your document, fixing the first one often resolves several others downstream.
HTML follows a strict nesting model where elements must be closed in last-in, first-out (LIFO) order. Think of it like stacking boxes: you must close the innermost box before you can close the one containing it. When you write </li> but a <span> inside that <li> is still open, the browser sees a conflict — you're trying to close the outer element while an inner element is dangling.
This error typically occurs due to one of these situations:
- A missing closing tag for a nested element (e.g., forgetting
</span>inside a<li>). - Misordered closing tags where you accidentally close elements in the wrong sequence.
- Typos in tag names where the intended closing tag doesn't match the opening tag, leaving the real element unclosed.
While browsers use error-recovery algorithms to guess what you meant, different browsers may handle malformed nesting differently. This can lead to inconsistent rendering, broken styles, and unexpected DOM structures. Screen readers and other assistive technologies rely on a well-formed DOM tree, so broken nesting can also cause accessibility issues. Keeping your HTML properly nested ensures predictable behavior across all browsers and tools.
How to fix it
- Locate the line referenced in the validator error. It will tell you which closing tag was seen and which elements were still open.
- Trace backward from the closing tag to find the unclosed element.
- Add the missing closing tag in the correct position, or reorder closing tags so they mirror the opening tags in reverse.
- Re-validate to confirm the fix, since one nesting error can cascade into multiple warnings.
Examples
❌ Missing closing tag for a nested element
<ul>
<li><span>Item one</li>
<li>Item two</li>
</ul>
The <span> inside the first <li> is never closed. The validator sees </li> but <span> is still open.
✅ Fixed: close the inner element first
<ul>
<li><span>Item one</span></li>
<li>Item two</li>
</ul>
❌ Misordered closing tags
<p>This is <strong><em>important</strong></em> text.</p>
Here </strong> appears before </em>, but <em> was opened inside <strong>, so <em> must close first.
✅ Fixed: close tags in reverse order
<p>This is <strong><em>important</em></strong> text.</p>
❌ Multiple levels of broken nesting
<div>
<section>
<p>Hello <a href="/">world</p>
</section>
</div>
The <a> element is never closed. The </p> tag is encountered while <a> is still open.
✅ Fixed: close the anchor before the paragraph
<div>
<section>
<p>Hello <a href="/">world</a></p>
</section>
</div>
❌ Typo in a closing tag causing a mismatch
<p>Click <a href="/help">here</b> for help.</p>
The closing </b> doesn't match the opening <a>, so the <a> element remains open when </p> is reached.
✅ Fixed: use the correct closing tag
<p>Click <a href="/help">here</a> for help.</p>
A helpful way to avoid this error is to visualize your HTML as an outline — every level of indentation represents a nesting level, and closing tags should "unwind" in exact reverse order. Many code editors also offer bracket and tag matching features that highlight mismatched or unclosed tags in real time.
An element with role="tab" requires a corresponding element with role="tabpanel" in the same document. Without this pairing, assistive technologies cannot associate the tab with the content it controls.
The WAI-ARIA specification defines a tab interface as a set of layered content areas, where only one panel is visible at a time. Each role="tab" element must reference a role="tabpanel" element through the aria-controls attribute, and each role="tabpanel" should reference its tab back using aria-labelledby.
The tabs themselves must be wrapped in a container with role="tablist". The selected tab gets aria-selected="true", while inactive tabs get aria-selected="false". Each tabpanel that is not currently visible should be hidden with the hidden attribute or equivalent CSS.
The W3C validator flags this error when it finds a role="tab" element but no matching role="tabpanel" exists in the document. This can happen when the tab panels are missing entirely, or when they exist but lack the role="tabpanel" attribute.
Invalid example
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2">Tab 2</button>
</div>
<div id="panel-1">Content for tab 1</div>
<div id="panel-2" hidden>Content for tab 2</div>
The two div elements exist but have no role="tabpanel", so the validator reports the error.
Valid example
<div role="tablist">
<button role="tab" aria-selected="true" aria-controls="panel-1" id="tab-1">Tab 1</button>
<button role="tab" aria-selected="false" aria-controls="panel-2" id="tab-2">Tab 2</button>
</div>
<div role="tabpanel" id="panel-1" aria-labelledby="tab-1">
Content for tab 1
</div>
<div role="tabpanel" id="panel-2" aria-labelledby="tab-2" hidden>
Content for tab 2
</div>
Each role="tab" now has a corresponding role="tabpanel". The aria-controls on each tab points to the id of its panel, and aria-labelledby on each panel points back to the id of its tab.
The HTML specification explicitly forbids certain Unicode code points from appearing anywhere in an HTML document. These include most ASCII control characters (such as U+0000 NULL, U+0008 BACKSPACE, or U+000B VERTICAL TAB), as well as Unicode noncharacters like U+FFFE, U+FFFF, and the range U+FDD0 to U+FDEF. When the W3C validator encounters one of these code points, it reports the error "Forbidden code point" followed by the specific value.
These characters are forbidden because they have no defined meaning in HTML and can cause unpredictable behavior across browsers and platforms. Some may be silently dropped, others may produce rendering glitches, and some could interfere with parsing. Screen readers and other assistive technologies may also behave erratically when encountering these characters, making this an accessibility concern as well.
How forbidden characters get into your code
- Copy-pasting from external sources like word processors, PDFs, or databases that embed invisible control characters.
- Faulty text editors or build tools that introduce stray bytes during file processing.
- Incorrect character encoding where byte sequences are misinterpreted, resulting in forbidden code points.
- Programmatic content generation where strings aren't properly sanitized before being inserted into HTML.
How to fix it
- Identify the character and its location. The validator message includes the code point (e.g.,
U+000B) and the line number. Use a text editor that can show invisible characters (such as VS Code with the "Render Whitespace" or "Render Control Characters" setting enabled, or a hex editor). - Remove or replace the character. In most cases, the forbidden character serves no purpose and can simply be deleted. If it was standing in for a space or line break, replace it with the appropriate standard character.
- Sanitize content at the source. If your HTML is generated dynamically, strip forbidden code points from strings before outputting them. In JavaScript, you can use a regular expression to remove them.
// Remove common forbidden code points
text = text.replace(/[\x00-\x08\x0B\x0E-\x1F\x7F\uFDD0-\uFDEF\uFFFE\uFFFF]/g, '');
Examples
Incorrect — contains a forbidden control character
In this example, a vertical tab character (U+000B) is embedded between "Hello" and "World." It is invisible in most editors but the validator will flag it.
<!-- The ␋ below represents U+000B VERTICAL TAB, an invisible forbidden character -->
<p>Hello␋World</p>
Correct — forbidden character removed
<p>Hello World</p>
Incorrect — NULL character in an attribute value
A U+0000 NULL character may appear inside an attribute, often from programmatic output.
<!-- The attribute value contains a U+0000 NULL byte -->
<div title="Some�Text">Content</div>
Correct — NULL character removed from attribute
<div title="SomeText">Content</div>
Allowed control characters
Not all control characters are forbidden. The following are explicitly permitted in HTML:
U+0009— Horizontal tab (regular tab character)U+000A— Line feed (newline)U+000D— Carriage return
<pre>Line one
Line two with a tab</pre>
This is valid because it uses only standard whitespace characters (U+000A for the newline and U+0009 for the tab).
When the parser sees </, it expects the start of an end tag — specifically, a sequence like </tagname> where the tag name immediately follows the slash with no spaces, invalid characters, or other unexpected content before the closing >. Anything else is considered "garbage" because it doesn't conform to the HTML syntax rules for end tags.
This error matters for several reasons. First, browsers enter error-recovery mode when they encounter malformed markup, and different browsers may recover differently, leading to inconsistent rendering. Second, assistive technologies like screen readers rely on a well-formed DOM tree, so malformed tags can disrupt accessibility. Third, what seems like a minor typo can cascade into larger parsing problems — the parser may misinterpret the document structure, causing elements to nest incorrectly or content to disappear.
Here are the most common causes of this error:
- A space between the slash and the tag name:
</ div>instead of</div>. - Trying to close a void element:
</br>,</img>, or</input>. Void elements must not have end tags in HTML. - Accidental or malformed sequences:
</--,</>, or</3appearing in content. - Displaying markup as text without escaping: Writing
</div>in a paragraph when you meant to show it literally, instead of using</div>. - Typos or leftover characters:
</p>extraor</p.>where stray characters follow the tag name.
To fix this error, inspect the line indicated by the validator and determine what you intended. If it should be a closing tag, correct the syntax. If it should be visible text, escape the < as <. If it's an attempt to close a void element, simply remove the end tag entirely.
Examples
Space inside the end tag
A space between </ and the tag name triggers the error:
<!-- ❌ Triggers: Garbage after "</" -->
<p>Hello world.</ p>
<!-- ✅ Fixed: no space after the slash -->
<p>Hello world.</p>
Trying to close a void element
Void elements like br, hr, img, and input must not have end tags:
<!-- ❌ Triggers: Garbage after "</" -->
<p>Line one.</br>Line two.</p>
<!-- ✅ Fixed: use <br> without a closing tag -->
<p>Line one.<br>Line two.</p>
Unescaped markup in text content
If you want to display HTML code as readable text, escape the angle brackets:
<!-- ❌ Triggers: Garbage after "</" -->
<p>To close a paragraph, use </p> at the end.</p>
<!-- ✅ Fixed: escape the angle brackets -->
<p>To close a paragraph, use <code></p></code> at the end.</p>
Accidental or malformed sequences
Stray characters after </ that don't form a valid tag name:
<!-- ❌ Triggers: Garbage after "</" -->
<p>I </3 cats</p>
<!-- ✅ Fixed: escape the less-than sign -->
<p>I </3 cats</p>
Full document example
<!-- ❌ Triggers the error -->
<!doctype html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<p>This has a bad closing tag.</ p>
<p>Show code: </div> in text.</p>
</body>
</html>
<!-- ✅ Fixed version -->
<!doctype html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<p>This has a correct closing tag.</p>
<p>Show code: <code></div></code> in text.</p>
</body>
</html>
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
h2inside anh1hoping to create a visual "main heading + subtitle" pattern. This is invalid. Instead, use separate heading elements or use aspanorpelement 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 openingh3tags 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.
When the HTML parser encounters an <svg> or <math> tag, it switches from the HTML namespace into a foreign namespace (SVG or MathML, respectively). Inside these foreign contexts, only elements defined by those specifications are valid. The HTML <img> element does not exist in the SVG or MathML namespaces, so placing it there causes a parsing conflict and triggers the W3C validator error: "HTML start tag img in a foreign namespace context."
This matters for several reasons. Browsers handle this situation inconsistently — some may break out of the foreign namespace to render the <img>, while others may ignore it entirely or produce unexpected layout results. This inconsistency means your page may look correct in one browser but be broken in another. Beyond rendering issues, assistive technologies rely on proper namespace boundaries to interpret content. An <img> in the wrong namespace may lose its accessibility semantics, meaning the alt text could go unannounced to screen reader users.
How to fix it
The fix depends on which foreign namespace context contains the <img>:
Inside <svg>: Replace <img> with the SVG <image> element. Note that SVG's <image> uses the href attribute (not src) and requires x, y, width, and height attributes for positioning and sizing. Unfortunately, SVG's <image> element does not support an alt attribute directly — use a <title> child element or aria-label to provide an accessible name.
Inside <math>: Move the <img> outside the <math> element entirely, or place it inside an <mtext> element. The <mtext> element in MathML is designed to hold text content and, per the HTML parsing rules, can contain embedded HTML elements.
Examples
Incorrect: <img> inside <svg>
<svg width="200" height="200">
<img src="diagram.png" alt="A diagram" width="200" height="200">
</svg>
Correct: using SVG <image> element
<svg width="200" height="200" role="img" aria-label="A diagram">
<image href="diagram.png" x="0" y="0" width="200" height="200" />
</svg>
Correct: with an accessible name via <title>
<svg width="200" height="200" role="img" aria-labelledby="diagram-title">
<title id="diagram-title">A diagram</title>
<image href="diagram.png" x="0" y="0" width="200" height="200" />
</svg>
Incorrect: <img> inside <math>
<math>
<img src="equation.png" alt="x squared plus one">
</math>
Correct: <img> inside <mtext> within <math>
<math>
<mtext>
<img src="equation.png" alt="x squared plus one">
</mtext>
</math>
Correct: <img> moved outside <math>
<img src="equation.png" alt="x squared plus one">
Incorrect: mixed HTML content inside <svg>
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<img src="icon.png" alt="Icon" width="32" height="32">
<text x="50" y="80">Hello</text>
</svg>
Correct: using <image> alongside other SVG elements
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<image href="icon.png" x="10" y="10" width="32" height="32" aria-label="Icon" />
<text x="50" y="80">Hello</text>
</svg>
If you need to place HTML content alongside or on top of an SVG, consider using the <foreignObject> SVG element, which explicitly creates an HTML namespace context within SVG:
<svg width="300" height="150">
<rect width="300" height="150" fill="#eee" />
<foreignObject x="10" y="10" width="100" height="100">
<img src="icon.png" alt="Icon" width="32" height="32">
</foreignObject>
</svg>
The <foreignObject> approach is especially useful when you need full HTML capabilities — such as alt text on <img>, form controls, or rich text — inside an SVG graphic.
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.
Pro Trial
Full Pro access. Cancel anytime.
Start Pro Trial →Join teams across 40+ countries