Skip to main content

How to Fix Missing or Incorrect Landmarks

Landmarks are regions of a page that assistive technologies expose as a navigation mechanism. Screen reader users can jump directly between landmarks, bypassing repetitive content and reaching the section they need in seconds. When landmarks are missing, duplicated, or improperly nested, this navigation breaks down and users are forced to traverse content linearly.

This guide covers every landmark-related rule flagged by axe-core, the WCAG success criteria behind them, and how to fix each issue with practical code changes.

WCAG Success Criteria

Landmark issues map to two Level A success criteria:

  • SC 1.3.1 Info and Relationships (Level A) requires that information, structure, and relationships conveyed through presentation are available programmatically. Using semantic landmark elements ensures that the visual page structure is exposed to assistive technologies.
  • SC 2.4.1 Bypass Blocks (Level A) requires a mechanism to bypass blocks of content that are repeated on multiple pages. Landmarks provide one such mechanism: screen reader users can skip the header and navigation by jumping directly to the main landmark.

HTML5 Landmark Elements and Their ARIA Roles

HTML5 introduced semantic elements that implicitly carry ARIA landmark roles. You do not need to add role attributes when you use these elements correctly:

  • <header> maps to banner when it is a direct child of <body> (not nested inside <article>, <aside>, <main>, <nav>, or <section>).
  • <nav> maps to navigation.
  • <main> maps to main.
  • <aside> maps to complementary.
  • <footer> maps to contentinfo when it is a direct child of <body> (same scoping rules as <header>).
  • <section> maps to region only when it has an accessible name (via aria-label or aria-labelledby).
  • <form> maps to form only when it has an accessible name.

axe-core Rules Reference

Here is every landmark rule axe-core checks, what it means, and how to resolve it.

landmark-one-main — The page must contain exactly one main landmark. Without it, screen reader users have no way to jump to the primary content. Fix: wrap your primary content in a <main> element.

bypass — The page must provide a way to bypass repeated blocks of content. A <main> landmark satisfies this requirement. Alternatively, add a skip link as the first focusable element on the page.

region — All page content must be contained within a landmark region. Any text or interactive element outside a <header>, <nav>, <main>, <aside>, or <footer> will trigger this rule. Fix: ensure every visible element on the page lives inside an appropriate landmark.

landmark-unique — If more than one landmark of the same type exists, each must have a unique accessible name. Two <nav> elements without labels are indistinguishable in the landmarks list. Fix: add aria-label to each one.

landmark-banner-is-top-level — The banner landmark must not be nested inside another landmark. Fix: move your <header> so it is a direct child of <body>, not inside <main> or <section>.

landmark-contentinfo-is-top-level — The contentinfo landmark must not be nested inside another landmark. Fix: move your <footer> so it is a direct child of <body>.

landmark-no-duplicate-banner — The page must not have more than one banner landmark. If you have a <header> inside an <article>, it does not create a banner landmark, so this is usually caused by having two top-level <header> elements or two elements with role="banner". Fix: keep only one top-level <header>.

landmark-no-duplicate-contentinfo — The page must not have more than one contentinfo landmark. Fix: keep only one top-level <footer>.

landmark-complementary-is-top-level — The complementary landmark (<aside>) must be a top-level landmark or nested directly inside the main landmark. Fix: move <aside> out of <nav>, <header>, <footer>, or other non-main landmarks.

landmark-main-is-top-level — The main landmark must not be nested inside another landmark. Fix: ensure <main> is a direct child of <body> (or a non-landmark wrapper like a layout <div>).

Fixing a Page Without Landmarks

The most common issue is a page built entirely with <div> elements and no semantic structure. Here is a typical broken page and the corrected version.

Before — no landmarks:

<body>
  <div class="header">
    <div class="logo">Acme Corp</div>
    <div class="nav">
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </div>
  </div>
  <div class="sidebar">
    <div class="widget">Related links</div>
  </div>
  <div class="content">
    <h1>Welcome</h1>
    <p>Main content here.</p>
  </div>
  <div class="footer">
    <p>&copy; 2026 Acme Corp</p>
  </div>
</body>

After — correct landmark structure:

<body>
  <header>
    <a href="/">Acme Corp</a>
    <nav aria-label="Main">
      <a href="/">Home</a>
      <a href="/about">About</a>
      <a href="/contact">Contact</a>
    </nav>
  </header>
  <aside aria-label="Sidebar">
    <p>Related links</p>
  </aside>
  <main>
    <h1>Welcome</h1>
    <p>Main content here.</p>
  </main>
  <footer>
    <p>&copy; 2026 Acme Corp</p>
  </footer>
</body>

This structure produces the following landmarks list in a screen reader: banner, navigation "Main", complementary "Sidebar", main, contentinfo. Every element on the page is inside a landmark, satisfying the region rule.

Labeling Multiple Landmarks of the Same Type

Pages commonly have multiple <nav> or <aside> elements. Without labels, a screen reader announces them identically, making them useless as navigation targets.

<!-- Before: two unlabeled nav elements -->
<nav>
  <a href="/">Home</a>
  <a href="/products">Products</a>
</nav>
<nav>
  <a href="/privacy">Privacy</a>
  <a href="/terms">Terms</a>
</nav>

<!-- After: each nav has a unique label -->
<nav aria-label="Main">
  <a href="/">Home</a>
  <a href="/products">Products</a>
</nav>
<nav aria-label="Legal">
  <a href="/privacy">Privacy</a>
  <a href="/terms">Terms</a>
</nav>

You can also use aria-labelledby if the landmark contains a visible heading:

<aside aria-labelledby="sidebar-title">
  <h2 id="sidebar-title">Related Articles</h2>
  <ul>
    <li><a href="/article-1">Article 1</a></li>
    <li><a href="/article-2">Article 2</a></li>
  </ul>
</aside>

Complete Page Structure Template

This template satisfies every axe-core landmark rule. Use it as a starting point for new pages:

<body>
  <a href="#main-content" class="sr-only focus:not-sr-only">
    Skip to main content
  </a>

  <header>
    <a href="/">Site Name</a>
    <nav aria-label="Main">
      <ul>
        <li><a href="/features">Features</a></li>
        <li><a href="/pricing">Pricing</a></li>
        <li><a href="/docs">Docs</a></li>
      </ul>
    </nav>
  </header>

  <main id="main-content">
    <h1>Page Title</h1>
    <p>Primary content.</p>

    <section aria-labelledby="section-features">
      <h2 id="section-features">Features</h2>
      <p>Section content.</p>
    </section>

    <aside aria-label="Related resources">
      <h2>Related Resources</h2>
      <p>Sidebar content inside main.</p>
    </aside>
  </main>

  <footer>
    <nav aria-label="Footer">
      <a href="/privacy">Privacy</a>
      <a href="/terms">Terms</a>
    </nav>
    <p>&copy; 2026 Site Name</p>
  </footer>
</body>

Nested Landmarks

Some landmarks can be nested; others cannot. The rules are straightforward:

  • banner and contentinfo must be top-level. They cannot be nested inside main, navigation, complementary, or any other landmark.
  • main must be top-level. It cannot be nested inside another landmark.
  • navigation can be nested inside banner, main, complementary, or contentinfo. This is common and correct: a <nav> inside <header> is the standard pattern.
  • complementary must be top-level or nested directly inside main. It cannot be nested inside navigation, banner, or contentinfo.
  • region (labeled <section>) can be nested inside any landmark. Use it to subdivide main content into named regions.
  • form (labeled <form>) can be nested inside any landmark. A search form in the header is a common example.

A common mistake is wrapping the entire page in a <main> element, which places <header> and <footer> inside it and breaks the top-level requirement for banner and contentinfo:

<!-- Wrong: header and footer are inside main -->
<main>
  <header>...</header>
  <h1>Content</h1>
  <footer>...</footer>
</main>

<!-- Correct: header, main, and footer are siblings -->
<header>...</header>
<main>
  <h1>Content</h1>
</main>
<footer>...</footer>

Landmarks in Single-Page Applications

SPAs present unique challenges because the page shell remains static while content is loaded dynamically into a container. The key rules apply equally:

  • Maintain the same landmark structure as a traditional page: <header>, <nav>, <main>, <footer> as siblings.
  • Swap content inside <main>, not alongside it. Never remove or replace the <main> element itself during route changes.
  • After a route change, move focus to the <main> element or the new page heading. This ensures screen reader users know the content has changed.
  • Update the page <title> on every route change so the new context is announced.
  • If the SPA renders a modal dialog, the dialog itself does not need landmarks, but the underlying page structure must remain valid when the dialog is closed.
<!-- SPA shell -->
<header>
  <nav aria-label="Main">...</nav>
</header>

<main id="app-content">
  <!-- Route content is injected here -->
</main>

<footer>...</footer>

<script>
  // After route change:
  document.title = newPageTitle;
  document.getElementById('app-content').focus();
</script>

For the focus call to work, add tabindex="-1" to the <main> element so it can receive programmatic focus without appearing in the tab order.

Testing with Screen Reader Landmarks

The fastest way to verify your landmark structure is to open the landmarks list in a screen reader:

  • VoiceOver (macOS): Open the rotor with VO + U, then use the left/right arrow keys to navigate to the Landmarks list.
  • NVDA (Windows): Press D to jump to the next landmark, or open the Elements List with NVDA + F7 and select the Landmarks tab.
  • JAWS (Windows): Press R to jump to the next landmark, or press Insert + Ctrl + R to list all landmarks.
  • TalkBack (Android): Open the local context menu and select Landmarks.

A well-structured page should produce a landmarks list similar to this:

banner
  navigation "Main"
main
  region "Features"
  complementary "Related resources"
contentinfo
  navigation "Footer"

If you see unnamed landmarks, duplicate entries, or missing entries, go back and check the corresponding elements. You can also use browser developer tools: in Chrome, open the Accessibility panel in DevTools, expand the accessibility tree, and look for landmark roles on each element.

Automated tools like axe-core catch structural violations, but manual testing with a screen reader confirms the experience matches your intent. A page can pass all automated checks and still have a confusing landmark structure if the labels are vague or the regions do not match the visual layout.

Kas sinu veebisait on juurdepaasetav?

Skanni oma veebisaiti tasuta ja saa oma WCAG-skoor monikuminutiga.

Skanni oma saiti tasuta