auditmysitev2.0.2

No main-content region as a bypass target

landmarks/main-missing

WCAG success criterion
2.4.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, Navigation & Operation
Default severity
medium
axe-core rule
landmark-one-main

Why we flag this

Keyboard users have no reliable target to bypass repeated navigation blocks.

No element with role="main" (implicit via <main> or explicit) present.

What the rule checks

Scope. Every top-level document. A body without any content has nothing to structure and is not applicable.

Expectation. Flags a document without a rendered main landmark (main element or role="main", also inside an open shadow root), at the html element. While a modal dialog is open the absence concerns the moment of measurement: review instead. A hidden second main does not stand in for nor block the visible one. Best practice without a criterion; a missing bypass mechanism is headings/none.

Source. Best practice: WAI-ARIA 1.2 main role; ARIA11; axe landmark-one-main (bypass itself is headings/none, SC 2.4.1)

Detection: shared; needs dom, computed_style.

Failing example

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

missing_main_landmark.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Missing main landmark corpus case</title>
</head>
<body>
    <div>
        <h1>Page without a main landmark</h1>
        <p>No main element or role="main" anywhere on this page.</p>
    </div>
</body>
</html>

Passing example

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

landmark_main_in_shadow_root.htmlHTML
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Main landmark inside a shadow root corpus case</title>
</head>
<body>
    <!-- The page's landmarks live in an open shadow root, as in web-component
         app shells. Chrome's accessibility tree exposes the main landmark; a
         document.querySelectorAll('main') check does not see it and used to
         report a missing main. -->
    <app-shell></app-shell>
    <script>
        const root = document.querySelector('app-shell').attachShadow({ mode: 'open' });
        root.innerHTML =
            '<header><nav aria-label="Site"><a href="/">Home</a></nav></header>' +
            '<main><h1>Content in a shadow root</h1><p>Text.</p></main>' +
            '<footer>Footer</footer>';
    </script>
</body>
</html>

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