HTML Guides for section
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 W3C HTML validator enforces rules about which ARIA roles can be applied to specific HTML elements. The <section> element carries implicit semantics — it maps to the ARIA region role when it has an accessible name (e.g., via aria-label or aria-labelledby). While article is indeed a valid ARIA role defined in the WAI-ARIA specification, the HTML specification restricts which roles can override a <section> element’s native semantics. The allowed roles for <section> include alert, alertdialog, application, contentinfo, dialog, document, feed, log, main, marquee, navigation, none, note, presentation, search, status, tabpanel, and region — but not article.
This restriction exists because HTML already provides the <article> element, which carries the implicit article ARIA role natively. Using role="article" on a <section> creates a confusing mismatch: the element’s tag name suggests one semantic meaning while the role attribute declares another. This can confuse assistive technologies like screen readers, which may announce the element inconsistently depending on whether they prioritize the tag name or the explicit role.
The best fix depends on your intent:
- If the content is self-contained and independently meaningful (like a blog post, comment, or news story), replace the <section> with an <article> element. The <article> element already has the implicit article role, so no role attribute is needed.
- If the content is a thematic grouping within a page, keep the <section> element and remove the role attribute. Give it a heading or an aria-label so it functions as a meaningful landmark.
- If you specifically need the article role on a non-semantic element, use a <div> with role="article" instead, since <div> has no implicit role and allows any ARIA role to be applied.
Examples
Incorrect: role="article" on a <section>
This triggers the validation error because article is not a permitted role for <section>.
<section role="article">
<h2>Breaking news</h2>
<p>Details about the event.</p>
</section>
Correct: use <article> for self-contained content
The <article> element has the implicit article role, making the explicit role attribute unnecessary.
<article>
<h2>Breaking news</h2>
<p>Details about the event.</p>
</article>
Correct: use <section> without a conflicting role
If the content is a thematic grouping rather than a standalone piece, keep <section> and drop the role attribute. Adding an accessible name via aria-labelledby makes it a region landmark.
<section aria-labelledby="news-heading">
<h2 id="news-heading">Latest news</h2>
<p>Details about the event.</p>
</section>
Correct: use a <div> when you need an explicit article role
In rare cases where you cannot use the <article> element but need the article role, a <div> accepts any valid ARIA role.
<div role="article">
<h2>Breaking news</h2>
<p>Details about the event.</p>
</div>
Correct: nest <article> inside <section> for grouped articles
If you need both a thematic grouping and individual self-contained items, nest <article> elements inside a <section>.
<section aria-labelledby="stories-heading">
<h2 id="stories-heading">Top stories</h2>
<article>
<h3>First story</h3>
<p>Story content.</p>
</article>
<article>
<h3>Second story</h3>
<p>Story content.</p>
</article>
</section>
As a general rule, prefer native HTML elements over ARIA roles whenever possible. The <article> element communicates the article role more reliably than any ARIA override, and it works consistently across all browsers and assistive technologies without additional attributes.
Use a valid landmark or list role: remove role="list" from the section, or replace the element with a proper list (ul/ol) or a container that supports role="list".
The role attribute must use values allowed by ARIA for the given context. A section element is a landmark and must not be given role="list". If you intend to mark up a list of items, use semantic list elements: ul/ol with li. If you truly need ARIA list semantics (e.g., for custom components), use a neutral container (div) with role="list" and child elements with role="listitem". Prefer native HTML lists over ARIA roles because they provide built-in semantics and better accessibility. Examples:
- Native list: use ul + li.
- ARIA list (only if native markup isn’t possible): div role="list" containing div role="listitem".
HTML Examples
Example showing the validation error
<section role="list">
<div>Item A</div>
<div>Item B</div>
</section>
Fixed using native list semantics (recommended)
<ul>
<li>Item A</li>
<li>Item B</li>
</ul>
Fixed using ARIA roles on neutral elements (when custom UI prevents native lists)
<div role="list">
<div role="listitem">Item A</div>
<div role="listitem">Item B</div>
</div>
The value section does not exist in the WAI-ARIA specification. ARIA defines a specific set of role values, and section is not among them. This is likely a confusion between the HTML element name <section> and the ARIA role region, which is the role that the <section> element implicitly maps to. Because section is not a recognized role, the validator rejects it as an invalid value.
This matters for several reasons. First, assistive technologies like screen readers rely on ARIA roles to communicate the purpose of elements to users. An unrecognized role value may be ignored entirely or cause unexpected behavior, degrading the experience for users who depend on these tools. Second, the <section> element already carries native semantics equivalent to role="region" (when it has an accessible name), so adding a redundant or incorrect role provides no benefit and introduces potential problems.
According to the ARIA in HTML specification, you should generally avoid setting a role on elements that already have appropriate native semantics. The <section> element’s implicit role is region, so explicitly adding role="region" is redundant in most cases. The simplest and best fix is to remove the role attribute altogether and let the native HTML semantics do their job.
If you do need to override an element’s role for a specific design pattern (for example, turning a <section> into a navigation landmark), use a valid ARIA role from the WAI-ARIA specification.
Examples
Incorrect: using the invalid section role
<section role="section">
<h2>About Us</h2>
<p>Learn more about our team.</p>
</section>
This triggers the validation error because section is not a valid ARIA role value.
Correct: remove the role attribute
<section>
<h2>About Us</h2>
<p>Learn more about our team.</p>
</section>
The <section> element already provides the correct semantics. No role attribute is needed.
Correct: use a valid ARIA role if needed
If you have a specific reason to assign a role, use a valid one. For example, if a <section> is being used as a navigation landmark:
<section role="navigation" aria-label="Main navigation">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</section>
In practice, you would typically use a <nav> element instead, which has the navigation role natively. This example simply illustrates that if you do apply a role, it must be a valid ARIA role value.
Correct: explicit region role with an accessible name
If you want to explicitly mark a section as a named region landmark, you can use role="region" along with an accessible name. However, this is redundant when using <section> with an aria-label or aria-labelledby, since the browser already maps it to region:
<!-- Preferred: native semantics handle the role -->
<section aria-labelledby="features-heading">
<h2 id="features-heading">Features</h2>
<p>Explore our product features.</p>
</section>
<!-- Also valid but redundant -->
<section role="region" aria-labelledby="features-heading">
<h2 id="features-heading">Features</h2>
<p>Explore our product features.</p>
</section>
Both are valid HTML, but the first approach is cleaner and follows the principle of relying on native semantics whenever possible.
The <section> element defines a standalone thematic grouping within a document — think chapters, tabbed panels, or distinct parts of a page like “About Us” or “Contact.” According to the HTML specification, each <section> should generally include a heading that identifies its content. When a <section> lacks a heading, the validator raises this warning because the element isn’t being used as intended.
This matters for several reasons:
Accessibility. Screen readers and other assistive technologies use headings to build an outline of the page. When a user navigates by sections, the heading is what identifies each one. A <section> without a heading appears as an “untitled section” in the document outline, which makes it difficult or impossible for assistive technology users to understand the page structure or jump to the content they need.
Semantics. The whole purpose of <section> is to group related content under a common theme, and that theme should be labeled with a heading. If your content doesn’t need a heading, it may not be a true “section” in the semantic sense, and a <div> (which carries no semantic meaning) might be a better fit.
Document outline. Browsers and tools that generate document outlines rely on headings within sectioning elements. Missing headings create gaps in the outline, reducing the usefulness of the page structure.
How to fix it
You have three main options:
-
Add a heading — Place an <h2>–<h6> element at the beginning of the <section>. This is the preferred solution when the section genuinely represents a thematic block of content.
-
Use aria-label or aria-labelledby — If a visible heading doesn’t suit your design, you can label the section for assistive technologies using an ARIA attribute. This resolves the accessibility concern, though the validator may still show the warning.
-
Switch to <div> — If the content doesn’t represent a meaningful, identifiable section of the document, replace <section> with a <div>. There’s no expectation for a <div> to have a heading.
Examples
❌ Section without a heading
This triggers the warning because neither <section> has a heading:
<h1>All about guitars</h1>
<section>
<p>Acoustic, electric, classical... we have them all!</p>
</section>
<section>
<p>Analog, digital, portable...</p>
</section>
✅ Fixed: Adding headings to each section
<h1>All about guitars</h1>
<section>
<h2>Guitar types</h2>
<p>Acoustic, electric, classical... we have them all!</p>
</section>
<section>
<h2>Amplifiers</h2>
<p>Analog, digital, portable...</p>
</section>
✅ Fixed: Using aria-label when a visible heading isn’t appropriate
<section aria-label="Guitar types">
<p>Acoustic, electric, classical... we have them all!</p>
</section>
✅ Fixed: Using aria-labelledby to reference an existing element
<section aria-labelledby="guitar-heading">
<span id="guitar-heading" class="visually-hidden">Guitar types</span>
<p>Acoustic, electric, classical... we have them all!</p>
</section>
✅ Fixed: Replacing with <div> when no section semantics are needed
If you’re only using the element as a styling wrapper and the content doesn’t form a distinct thematic group, use a <div> instead:
<h1>All about guitars</h1>
<div class="content-block">
<p>Acoustic, electric, classical... we have them all!</p>
</div>
<div class="content-block">
<p>Analog, digital, portable...</p>
</div>
As a general rule, reach for <section> when your content has a clear topic that deserves a heading, and use <div> when you need a generic container for layout or styling purposes.
The word “stray” in this error message means the validator encountered a start tag in a place where no element of that kind is allowed according to the HTML specification. The <section> element is flow content, so it must appear inside the <body> element (or inside another element that accepts flow content, such as <main>, <article>, <div>, etc.). When the validator sees <section> somewhere it can’t legally exist, it flags it as “stray.”
There are several common causes for this error:
- Content placed after </body> or </html>: The most frequent cause. Extra markup exists beyond the closing tags of the document body.
- Premature closing of the <body>: An extra or misplaced </body> tag earlier in the document causes the browser to consider the body closed, making any subsequent <section> stray.
- Nesting inside elements that don’t accept flow content: Placing <section> directly inside a <p>, <span>, <a>, or other phrasing-content-only element. Since these elements can’t contain block-level flow content, the browser implicitly closes the parent, leaving <section> in an invalid position.
- Malformed or unclosed tags: Earlier syntax errors — like a missing closing > on a tag — can shift the parser’s understanding of the document tree, causing downstream elements to appear stray.
This matters because browsers use error recovery when they encounter stray elements, and different browsers may handle the recovery differently. Your content could end up outside the visible document, be rendered inconsistently, or cause accessibility tools to misinterpret the page structure. Fixing this error ensures predictable rendering and a well-formed document.
Examples
Stray <section> after the closing </body> tag
This is the most common scenario. Content placed after </body> has nowhere valid to go:
<!-- ❌ Incorrect: section appears after </body> -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<h1>Welcome</h1>
<p>Some content.</p>
</body>
<section>
<h2>About</h2>
<p>This section is stray.</p>
</section>
</html>
Move the <section> inside the <body>:
<!-- ✅ Correct: section is inside <body> -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<h1>Welcome</h1>
<p>Some content.</p>
<section>
<h2>About</h2>
<p>This section is properly placed.</p>
</section>
</body>
</html>
Extra </body> tag causing a premature close
A duplicate closing tag can trick the parser into ending the body early:
<!-- ❌ Incorrect: extra </body> causes section to become stray -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<div>
<p>Main content.</p>
<!-- accidental extra closing tag -->
</div>
<section>
<h2>Updates</h2>
<p>This is now stray.</p>
</section>
</body>
</html>
Remove the extra </body> tag:
<!-- ✅ Correct: single </body> at the end -->
<!DOCTYPE html>
<html lang="en">
<head>
<title>Example</title>
</head>
<body>
<div>
<p>Main content.</p>
</div>
<section>
<h2>Updates</h2>
<p>This is correctly placed now.</p>
</section>
</body>
</html>
Nesting <section> inside a <p> element
The <p> element only accepts phrasing content. When the parser encounters a <section> inside a <p>, it implicitly closes the <p> first, which can leave the <section> in an unexpected position:
<!-- ❌ Incorrect: section nested inside a paragraph -->
<p>
Introduction text.
<section>
<h2>Details</h2>
<p>More info here.</p>
</section>
</p>
Separate the paragraph and section into siblings:
<!-- ✅ Correct: section is a sibling, not a child of <p> -->
<p>Introduction text.</p>
<section>
<h2>Details</h2>
<p>More info here.</p>
</section>
Unclosed tag causing downstream errors
A missing closing angle bracket on an earlier element can corrupt the parser’s view of the entire document tree:
<!-- ❌ Incorrect: missing > on the </div causes parsing issues -->
<body>
<div>
<p>Content here.</p>
</div
<section>
<h2>Topics</h2>
<p>This may be flagged as stray.</p>
</section>
</body>
Fix the malformed tag:
<!-- ✅ Correct: properly closed </div> -->
<body>
<div>
<p>Content here.</p>
</div>
<section>
<h2>Topics</h2>
<p>No longer stray.</p>
</section>
</body>
How to debug this issue
- Check the line number reported by the validator and look at what comes before the <section> tag — the problem is usually above it, not at the <section> itself.
- Search for extra closing tags like </body>, </html>, or </div> that might prematurely close a container.
- Verify parent elements — make sure <section> isn’t nested inside <p>, <span>, <a>, <button>, or other elements that only accept phrasing content.
- Use proper indentation to make the document hierarchy visually clear. Misplaced tags are much easier to spot in well-formatted code.
- Revalidate after each fix, since correcting one stray tag error often resolves multiple related warnings.
The <main> element serves a specific structural role: it identifies the primary content of the page, distinct from repeated elements like headers, footers, and navigation. Because of this unique purpose, the HTML specification strictly limits where <main> can appear in the document tree. Nesting <main> inside a <section> element violates these rules because <section> represents a thematic grouping of content — placing <main> inside it implies that the dominant page content is merely a subsection of something else, which is semantically contradictory.
According to the WHATWG HTML living standard, a hierarchically correct <main> element is one whose ancestor elements are limited to <html>, <body>, <div>, <form> (without an accessible name), and autonomous custom elements. This means <main> cannot be a descendant of <article>, <aside>, <footer>, <header>, <nav>, or <section>.
Why this matters
- Accessibility: Screen readers and assistive technologies use the <main> element as a landmark to let users skip directly to the primary content. When <main> is incorrectly nested inside <section>, assistive technologies may misinterpret the document structure, making navigation harder for users who rely on landmarks.
- Standards compliance: Browsers are lenient and will render the page regardless, but the semantic meaning is broken. Future browser features or tools that depend on correct document structure may not work as expected.
- Document structure clarity: The <main> element should clearly sit at the top level of your content hierarchy, making it immediately obvious to both developers and machines which part of the page is the primary content.
Additional rules for <main>
Beyond the ancestor restriction, remember that a document must not have more than one visible <main> element. If you use multiple <main> elements (for example, in a single-page application), all but one must have the hidden attribute specified.
Examples
Incorrect: <main> nested inside <section>
This structure places <main> as a descendant of <section>, which triggers the validation error:
<body>
<header>
<h1>My Website</h1>
</header>
<section>
<main>
<h2>Welcome</h2>
<p>This is the primary content of the page.</p>
</main>
</section>
</body>
Correct: <main> as a sibling of <section>
Move <main> out of the <section> so it is a direct child of <body>:
<body>
<header>
<h1>My Website</h1>
</header>
<main>
<h2>Welcome</h2>
<p>This is the primary content of the page.</p>
</main>
<section>
<h2>Related Topics</h2>
<p>Additional thematic content goes here.</p>
</section>
</body>
Correct: <section> elements inside <main>
If your primary content is divided into thematic sections, nest the <section> elements inside <main> — not the other way around:
<body>
<header>
<h1>My Website</h1>
</header>
<main>
<section>
<h2>Introduction</h2>
<p>An overview of the topic.</p>
</section>
<section>
<h2>Details</h2>
<p>A deeper dive into the subject.</p>
</section>
</main>
<footer>
<p>© 2024 My Website</p>
</footer>
</body>
Correct: <main> wrapped in a <div>
If your layout requires a wrapper element around <main>, a <div> is a valid ancestor:
<body>
<div class="layout-wrapper">
<header>
<h1>My Website</h1>
</header>
<main>
<h2>Welcome</h2>
<p>This is the primary content of the page.</p>
</main>
</div>
</body>
The key principle is simple: <main> defines the dominant content of the entire document, so it belongs at the top level of your content hierarchy. Sectioning elements like <section>, <article>, <aside>, <nav>, <header>, and <footer> should never wrap <main> — instead, they should be placed as children or siblings of it.
A section element automatically defines a landmark region, so adding role="region" is redundant.
According to the HTML specification and WAI-ARIA guidelines, sectioning elements such as section, nav, article, and aside already have implicit landmark roles. Adding an explicit role="region" to a section does not change its semantics, and HTML validators will warn against this unnecessary usage.
Incorrect Example:
<section role="region">
<h2>Contact Information</h2>
<p>Email us at info@example.com</p>
</section>
Correct Example:
<section>
<h2>Contact Information</h2>
<p>Email us at info@example.com</p>
</section>
If a region of the page does not have an accessible name and you want it to be a landmark, add a heading element (<h1>-<h6>) as the first child to label the region for assistive technologies. Avoid adding redundant ARIA role attributes to native landmark elements for better accessibility and HTML validation.
Ready to validate your sites?
Start your free trial today.