auditmysitev2.0.2

Multiple main landmarks

landmarks/main-duplicate

WCAG success criterion
1.3.1 (level A)
Outcome class
Hint only. An automated check that by design reports review hints only: its findings are marked for manual review, never as confirmed violations.
Area
Accessibility, Structure & Semantics
Default severity
medium
axe-core rule
landmark-no-duplicate-main

Why we flag this

Screen reader users who jump to the main content cannot tell which region is meant.

More than one element with role="main" (implicit or explicit).

What the rule checks

Scope. Documents with at least one rendered main landmark.

Expectation. Flags a document with more than one rendered main landmark (main or role="main"), at the second one. A main with the hidden attribute does not count: HTML explicitly allows hidden alternative views. Best practice without a criterion since 4.1.1 was removed.

Source. HTML §4.4.14 the main element (at most one main without the hidden attribute); WAI-ARIA 1.2 main; axe landmark-no-duplicate-main

Detection: shared; needs dom, computed_style.

Failing example

The check flags this for review. Corpus case landmark_granular. The page may contain further findings for other rules.

landmark_granular.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Granular landmark corpus case</title>
</head>
<body>
    <nav>
        <div role="banner">Banner nested inside a nav landmark (not top-level)</div>
        <div role="main">Main nested inside a nav landmark (not top-level)</div>
    </nav>
    <header>First header (duplicate banner 1 of 2)</header>
    <header>Second header (duplicate banner 2 of 2)</header>
    <footer>First footer (duplicate contentinfo 1 of 2)</footer>
    <footer>Second footer (duplicate contentinfo 2 of 2)</footer>
    <main>First main region (duplicate main 1 of 2)</main>
    <div role="main">Second main region (duplicate main 2 of 2)</div>
    <nav>Unnamed nav A</nav>
    <nav>Unnamed nav B</nav>
</body>
</html>

Passing example

The check passes here and reports nothing. Corpus case structure_landmark_duplicates. The page may contain further findings for other rules.

structure_landmark_duplicates.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Order history – Acme Hardware</title>
    <style>
        body { font: 16px/1.5 sans-serif; margin: 0 16px; }
        a { display: inline-block; min-width: 44px; min-height: 44px; line-height: 44px; }
        input, button { min-width: 44px; min-height: 44px; }
    </style>
</head>
<body>
    <!-- A single-page app shell (#783). The inactive view's main is hidden,
         which HTML allows (only one main without the hidden attribute). A
         promo widget inside main declares itself a banner, and a cookie note
         declares itself a second contentinfo. The article's header belongs to
         the article and is no banner. -->
    <a href="#orders" class="skip-link">Skip to content</a>
    <header id="site-header">
        <p>Acme Hardware</p>
    </header>
    <nav aria-label="Account">
        <ul>
            <li><a href="/account/">Account</a></li>
            <li><a href="/orders/">Orders</a></li>
        </ul>
    </nav>
    <main id="profile" hidden>
        <h1>Your profile</h1>
    </main>
    <main id="orders">
        <h1>Order history</h1>
        <div id="promo" role="banner">
            <p>Free delivery this week.</p>
        </div>
        <article>
            <header><h2>Order 2026-0412</h2></header>
            <p>Three boxes of wood screws.</p>
        </article>
    </main>
    <footer id="site-footer">
        <p>Acme Hardware, Berlin</p>
    </footer>
    <div id="cookie-note" role="contentinfo">
        <p>This site stores your basket in a cookie.</p>
    </div>
</body>
</html>

This page is generated from the rule catalogue and the rule contracts; see therule overview for how the outcome classes are derived.