All fix guides
NoticeAccessibility

Fix Missing Semantic HTML Landmarks (Div Soup)

Your page is built mostly from generic <div> and <span> elements instead of semantic landmark tags like <header>, <nav>, <main>, <article>, and <footer>. Landmarks tell screen readers, browsers, and AI crawlers what each region of the page is and where the primary content lives. Swapping the outermost structural divs for the correct HTML5 elements is a low-risk, markup-only fix that improves accessibility and makes your content easier for Google and answer engines to parse.

What this means

This notice fires when the audit finds your page built almost entirely from non-semantic containers (<div>, <span>) with few or no HTML5 landmark elements. The specific triggers are: no <main> wrapping the primary content (missing_main_landmark), no semantic tags at all (no_semantic_html), no <article> on content that reads like a self-contained post or page (missing_article_tag), a low ratio of semantic elements to total elements (low_semantic_html), or an unusually high count of nested divs relative to meaningful markup (excessive_div_soup, informally "div soup").

Semantic landmarks are the HTML5 elements that describe what a region is rather than just how it looks: <header>, <nav>, <main>, <article>, <section>, <aside>, and <footer>. A <div class="main-content"> looks identical to a <main> on screen, but only the second carries machine-readable meaning. Assistive technology, search crawlers, and AI extraction pipelines rely on that meaning to identify the page's primary content, skip repeated navigation, and understand hierarchy.

This is a notice, not a critical error. Your page still renders and stays indexable. But it is a genuine accessibility and content-clarity gap, and one of the cheapest structural improvements you can make.

Why it matters

For accessibility, landmarks are how screen reader users navigate. Tools like NVDA, JAWS, and VoiceOver let users jump directly between regions and list all landmarks on a page. A page with no <main> or <nav> forces those users to move through every element in order, with no way to skip the header and menu that repeat on each page. This maps to WCAG 2.1 success criteria 1.3.1 (Info and Relationships) and 2.4.1 (Bypass Blocks). It is a real usability problem, not a cosmetic one.

For classic Google ranking, semantic structure is not a direct ranking factor, but it influences how well Google understands your content. A single <main> cleanly separates the primary content from boilerplate, which helps Google focus on what the page is actually about. Clean structure also tends to correlate with the kind of well-built pages Google's helpful-content systems favor.

For AI answer engines, this site's focus, semantic HTML matters even more. ChatGPT, Perplexity, Google AI Overviews, and other LLM crawlers extract and cite the main content of a page. When your primary content sits inside a labeled <main> or <article>, these systems can reliably separate it from navigation, ads, and footers. Div soup forces them to guess the boundaries, and they often guess wrong: pulling in menu items, skipping your key answer, or failing to attribute a passage to your page. If you want to be quoted in an AI Overview or a Perplexity answer, giving crawlers an unambiguous content region is one of the highest-leverage structural moves you can make.

How to fix it

  1. 1

    Wrap your primary content in one <main>

    Every page should have exactly one <main> element holding the unique, primary content, not the header, nav, or footer. Find the outer div around your article body or page content and change it to <main>. There must be only one <main> per rendered page, and it must not be nested inside <article>, <header>, <nav>, <aside>, or <footer>. This single change resolves the most important trigger (missing_main_landmark) and gives screen readers a 'skip to content' target.

  2. 2

    Map your structural divs to the right tags

    Replace the top-level wrapper divs, not every div, with their semantic equivalents. The site header becomes <header>, the primary menu becomes <nav>, the site-wide footer becomes <footer>, a sidebar becomes <aside>, and a self-contained post or page becomes <article>. Inner styling divs can stay. Keep your existing classes on the new tags so your CSS keeps working: use <header class="site-header"> in place of <div class="site-header">.

  3. 3

    Use <article> for self-contained content

    If the page is a blog post, news story, or product page, that would make sense on its own (for example in an RSS feed or when syndicated), wrap it in <article>. This resolves missing_article_tag and signals to AI crawlers where the quotable, self-contained content is. Use <section> for distinct thematic groupings inside the article, and give each section a heading (<h2>/<h3>). Note that a <section> only becomes a navigable landmark when it has an accessible name, so add aria-labelledby pointing at its heading if you want it exposed as one.

  4. 4

    Name duplicate landmarks so they stay distinct

    If a page has more than one <nav> (for example a primary menu and footer links), give each an accessible name with aria-label: <nav aria-label="Primary"> and <nav aria-label="Footer">. This lets assistive tech tell them apart instead of announcing a wall of unnamed 'navigation' landmarks. Do not add redundant ARIA roles such as role="main" to a <main> or role="navigation" to a <nav>. The native element already carries the role.

  5. 5

    Fix it in the template, not page by page

    Landmarks belong in your layout template so the fix applies site-wide. In a theme or component framework, edit the shared header, footer, and layout files once. After editing, re-crawl the page and check it in your browser DevTools accessibility panel or a landmarks extension to confirm one <main>, a labeled <nav>, and a <header> and <footer> are all detected. Re-check after any dynamic content loads to be sure you still have exactly one <main>.

Example

<!-- Before: no landmarks, all divs -->
<div class="header">
  <div class="logo">Acme</div>
  <div class="menu">
    <a href="/">Home</a>
    <a href="/blog">Blog</a>
  </div>
</div>
<div class="content">
  <div class="post">
    <h1>How to bake sourdough</h1>
    <p>Start with an active starter...</p>
  </div>
</div>
<div class="footer">© 2026 Acme</div>

<!-- After: semantic landmarks -->
<header class="header">
  <div class="logo">Acme</div>
  <nav aria-label="Primary" class="menu">
    <a href="/">Home</a>
    <a href="/blog">Blog</a>
  </nav>
</header>
<main class="content">
  <article class="post">
    <h1>How to bake sourdough</h1>
    <p>Start with an active starter...</p>
  </article>
</main>
<footer class="footer">© 2026 Acme</footer>

Before (div soup) vs after (semantic landmarks). Note the single <main>, the labeled <nav>, and content wrapped in <article>.

Platform-specific steps

WordPress (block themes, Yoast, Rank Math)

Most modern block (FSE) themes already output <header>, <main>, and <footer> through template parts, so the issue usually comes from a page builder or a custom classic theme. On a block theme, open Appearance > Editor > Templates and set the content Group block's 'HTML element' to 'main' via the block settings. On a classic theme, edit header.php, footer.php, and the content template (single.php or page.php) to output <header>, <nav>, <main>, and <article>. Yoast and Rank Math handle meta and schema, not page markup, so they will not fix this. The theme templates are where the landmarks live.

Elementor / Divi and other page builders

Page builders are the most common cause of div soup because sections and containers render as nested divs by default. In Elementor, edit the container and set the HTML Tag dropdown (in the container's Layout or Advanced settings) to header, main, nav, article, or footer, setting your main content container to 'main'. Divi exposes a similar HTML element setting per section in the Advanced tab. Set these on the outermost containers only, not on every inner column.

Shopify

Landmarks live in your theme's Liquid layout and sections. Edit layout/theme.liquid so the header snippet sits inside <header>, the footer inside <footer>, and the {{ content_for_layout }} output inside a single <main id="MainContent">. Dawn-based themes already do this; older or heavily customized themes may not. For product and article templates, wrap the main content section in <article>.

Wix / Squarespace

These platforms generate the outer page shell for you and don't expose the raw HTML, so you generally can't hand-edit landmark tags. Current Wix and Squarespace templates output <header>, <main>, and <footer> automatically. If your audit still flags this, the cause is usually content rendered outside the main region, often inside a raw custom-code or HTML embed block. Move critical content out of embed widgets and into native sections so it sits inside the platform's <main>.

Next.js / React / raw HTML

In a component framework, put landmarks in your root layout so they apply everywhere. In the Next.js App Router, add <header>, <nav>, and <footer> in app/layout.tsx and wrap {children} in <main>, then use <article> inside individual page and post components. Watch for the common mistake of rendering multiple <main> elements when nesting layouts; keep exactly one per rendered page. Semantic tags are plain JSX, so no library is needed.

Free tool
Check this with the Heading Checker

Frequently asked

Is missing semantic HTML a Google ranking factor?

Not directly. Google has never confirmed semantic landmarks as a ranking signal, and pages with div soup can still rank. But landmarks help Google identify which part of the page is the primary content, which can improve how your content is interpreted and selected for snippets. Treat it as a content-clarity and accessibility improvement, not a ranking shortcut.

Can I have more than one <main> element on a page?

Only one <main> may be visible at a time. You can have multiple <article>, <section>, <nav>, and <aside> elements, and multiple <nav> or <aside> landmarks are fine as long as each is labeled with aria-label. Two visible <main> elements is invalid HTML and confuses assistive technology. If a framework keeps a second one in the DOM, it must carry the hidden attribute.

Do I need to replace every div with a semantic tag?

No, and you shouldn't. Divs are valid for layout and styling wrappers with no semantic meaning, such as flex containers, grid cells, and generic groupings. You only need semantic tags for the structural regions: header, nav, main, article, section, aside, and footer. Fix the outermost structural divs and leave inner styling divs alone.

Will adding landmarks change how my page looks?

No. Elements like <main>, <header>, and <article> are block-level and render the same as a <div> by default. If you keep your existing class names when you swap the tags (for example <header class="site-header">), your CSS still applies and nothing shifts visually. It is a markup-only change with no visual impact.

Why do AI crawlers care about semantic HTML?

AI answer engines like ChatGPT, Perplexity, and Google AI Overviews extract the main content of a page to summarize and cite it. A labeled <main> or <article> lets them cleanly separate your real content from navigation, ads, and footers. Div soup forces them to guess where content begins and ends, which leads to missed answers, garbled extractions, or your page not being cited at all.

Does your site have this issue?

Run a free, AI-powered audit and we’ll flag this and 150+ other checks in about a minute. No signup.

No signup needed. Results in under 60 seconds.

Related fixes