Developer Guides
ARIA Landmarks and Page Structure Done Right
Landmarks are screen-reader navigation aids — high-level regions that let a non-sighted user jump straight to the main content, the primary navigation, the search box, or the footer without tabbing through every link on the page. The rule that beats every other rule in this guide: use native HTML5 first. The elements <header>, <nav>, <main>, <aside>, and <footer> carry implicit landmark roles in every modern browser, with no ARIA attribute required. The only landmark with no native HTML equivalent is role="search" — that one you do have to declare on the form yourself.
Reach for the ARIA role only as a fallback when you literally cannot ship the native element — usually because you are skinning a third-party widget, embedding a legacy CMS region, or supporting a browser that still does not map the implicit role correctly. Layering role="banner" onto a <header> is redundant — and worse, it tempts you to add a second role="banner" elsewhere and end up with duplicate top-level banners. The most common landmark findings on a SweepHound scan are not missing landmarks but over-labelled and duplicated ones: two <main> elements, three unlabelled <nav> regions, a role="banner" on the marketing hero and the site <header>. Less ARIA, used precisely, is the standard answer.
Why landmarks matter
Sighted users skim a page in milliseconds — the logo signals the header, the column of links signals navigation, the big chunk of text signals the main content. Screen-reader users do not have that visual scan. Instead, JAWS, NVDA, and VoiceOver expose a dedicated keyboard shortcut for jumping between landmark regions: NVDA cycles with D, VoiceOver opens the rotor with VO+U and lets you arrow through landmarks, and JAWS uses R for regions plus INSERT+F7 for the full list. WebAIM's screen reader survey documents the broader navigation model and confirms landmarks are one of the top two strategies for getting to a known region of a page (alongside heading navigation).
Without landmarks, the only way to reach the main content is Tab, Tab, Tab through every utility link, every nav item, every breadcrumb on every page. With one <main> element, that becomes a single keystroke. The cost to ship is zero. The cost of getting it wrong — duplicated banners, missing main, three identical-sounding nav regions — is a screen-reader user reading “navigation, navigation, navigation” and giving up.
The 6 standard landmarks — when to use each
header → banner
The top-of-page region containing the logo, site title, and primary site navigation. A page should expose exactly one banner — the site-wide header — at the top level of the DOM. A <header> nested inside <article> or <section> does not map to the banner landmark — that is the spec working as designed, not a bug.
<header>
<a href="/"><img src="/logo.svg" alt="Acme"></a>
<nav aria-label="Primary">…</nav>
</header><div role="banner">
<a href="/"><img src="/logo.svg" alt="Acme"></a>
<nav aria-label="Primary">…</nav>
</div>nav → navigation
A region containing a major group of navigation links. You can have more than one — primary site nav, in-page section nav, breadcrumbs, footer utility nav — but each one must have a unique accessible name via aria-label or aria-labelledby so they are distinguishable in the screen-reader landmarks list.
<nav aria-label="Primary">
<a href="/products">Products</a>
<a href="/pricing">Pricing</a>
</nav>
<nav aria-label="Breadcrumb">
<ol>…</ol>
</nav>
<nav aria-label="Footer">
<a href="/legal">Legal</a>
<a href="/contact">Contact</a>
</nav><div role="navigation" aria-label="Primary">
<a href="/products">Products</a>
<a href="/pricing">Pricing</a>
</div>main → main
The primary unique content of the page — exactly one per page, not nested inside any other landmark. This is the single highest-value landmark on the page, because it is the destination for both the screen-reader landmark shortcut and the keyboard skip link.
<main id="main-content">
<h1>Article title</h1>
<p>…</p>
</main><div role="main" id="main-content">
<h1>Article title</h1>
<p>…</p>
</div>aside → complementary
A region of content tangentially related to the main content — a sidebar with related articles, a callout with author bio, a “you may also like” rail. If the content could stand on its own elsewhere on the site, it is probably complementary. Multiple <aside> elements are fine, but label them.
<aside aria-label="Related articles">
<h2>Related</h2>
<ul>…</ul>
</aside><div role="complementary" aria-label="Related articles">
<h2>Related</h2>
<ul>…</ul>
</div>footer → contentinfo
The site-wide footer: copyright, legal links, contact details, policy links. Exactly one per page at the top level of the DOM. As with <header>, a <footer> nested inside <article> does not map to the contentinfo landmark — only the top-level one does.
<footer>
<p>© 2026 Acme</p>
<nav aria-label="Footer">…</nav>
</footer><div role="contentinfo">
<p>© 2026 Acme</p>
<nav aria-label="Footer">…</nav>
</div>search → search (no native equivalent)
The one landmark with no native HTML5 sectioning equivalent. HTML gives you <form> but a form by itself does not carry a landmark role. To expose the site search to landmark navigation, declare role="search" on the search form. This is the one place in this guide where ARIA is the first answer, not the fallback.
<form role="search" action="/search" aria-label="Site search">
<label for="q" class="sr-only">Search</label>
<input id="q" type="search" name="q">
<button type="submit">Search</button>
</form>Decision tree
Run this in your head before every landmark you ship.
- Is there a native HTML5 element with the implicit role? Use it. Do not add ARIA on top.
- Is the form's purpose to search the site? Add
role="search"to the<form>. This is the one mandatory ARIA case. - Are you rebuilding a third-party widget where native is not an option? Add the equivalent ARIA role to the wrapping
<div>. - Do you have multiple landmarks of the same type (two
<nav>, two<aside>)? Addaria-label(oraria-labelledby) to each so they are distinguishable in the landmarks list.
Skip links and landmarks work together
A skip link plus a <main> landmark gives sighted keyboard users a one-Tab route to the main content, while screen-reader users get the same thing via the landmarks shortcut. The two patterns reinforce each other — see our keyboard navigation guide for the full skip-link pattern.
<a href="#main-content" class="sr-only focus:not-sr-only
focus:absolute focus:z-50 focus:top-4 focus:left-4
focus:rounded-md focus:bg-ink focus:px-4 focus:py-2
focus:text-white">
Skip to main content
</a>
<header>…</header>
<nav aria-label="Primary">…</nav>
<main id="main-content">
<h1>Page title</h1>
…
</main>
<footer>…</footer>Common false positives and gotchas
- Multiple
<main>elements. Routing components and layout templates sometimes render two — one in the layout, one in the page. Scanners flag this. Fix: keep exactly one, at the top level, and pass children into it. role="banner"on a<header>. Redundant — the implicit role is already there — and most scanners and many assistive tech stacks treat the duplication as a separate banner. Fix: remove the ARIA attribute.<nav>outside the main page navigation. A card with “next / previous” controls does not need to be a navigation landmark — it is a control group inside content. Fix: use<div>with anaria-labeldescribing the group, and reserve<nav>for major navigation regions.- Missing
<main>. The page has a<header>and a<footer>but the actual content sits in an unlabelled<div>. Screen-reader users have no landmark for it. Fix: wrap the page content in a<main>element. - Unlabelled multiple
<nav>regions. Primary nav and footer nav both reported as just “navigation, navigation” in the landmarks list. Fix:aria-label="Primary"on one andaria-label="Footer"on the other.
Testing landmarks by hand
Two-minute manual check, no tooling required. On Windows with NVDA: load the page, then press D repeatedly to cycle through every landmark. The announcements should map cleanly onto your mental model of the page: banner, primary navigation, main, complementary, contentinfo. On macOS with VoiceOver: press VO+U to open the rotor and arrow over to Landmarks — you get the same list, organized hierarchically. If two regions announce identically (“navigation, navigation”), they need distinguishing labels. If you cannot find a landmark for the main content, you are missing <main>. For the full manual sweep, see our manual accessibility checklist and our deeper screen-reader testing guide.
Frequently asked questions
- Should every page have exactly one <main>?
- Yes. The W3C HTML and ARIA specs both define <main> (and role="main") as singletons within a document — one per page, not nested inside any other landmark. Some routing setups accidentally render two (one in the layout, one in the page). When a scanner flags duplicate main landmarks, the fix is structural: pick one container, render it once, and pass everything else as children. The exception is documents with multiple <main> elements where all but one carry the hidden attribute (for SPA route transitions, for example) — those do not surface to assistive tech and are fine.
- Can I have multiple <nav> elements?
- Yes — primary site nav, breadcrumbs, in-page section nav, and footer utility nav can all be <nav>. The hard requirement is that each <nav> region must have a unique accessible name via aria-label or aria-labelledby. Otherwise they all show up as "navigation" in the landmarks list and the user cannot tell which is which. Common labels: "Primary", "Breadcrumb", "Footer", "On this page", "Pagination". Keep the label short — screen readers read it every time the user lands on that region.
- Does the search role still need a label?
- If you only have one search form on the page, an aria-label is recommended but not strictly required — "search" already communicates the purpose. Once you ship a second search (e.g. a header site search plus an in-page filter search), each needs a distinct aria-label so the landmarks list disambiguates them. As a baseline habit, label every search landmark — "Site search", "Filter results", "Help center search" — and you will never have to debug a missing-label finding.
- Will SweepHound flag missing landmarks?
- Yes — SweepHound's dual-engine scan (axe-core plus IBM Equal Access, both available on every paid plan) flags missing <main>, duplicate landmarks, unlabelled multiple landmarks of the same type, and redundant ARIA roles on native sectioning elements. It will not, and cannot, tell you whether the landmarks you do have match the user's mental model of the page — that one needs a quick screen-reader pass. Per Deque's Automated Accessibility Coverage Report, Deque reported automated tests identified 57.38% of issue instances by volume in its dataset — based on 2,000+ audits across 13,000+ pages and ~300K issues — and landmark structure is one of the categories where automated coverage is high but never complete.
How SweepHound checks landmarks
On every scan we evaluate landmark structure across the page tree: we detect missing <main> regions, duplicated landmarks (two banners, two contentinfos, two mains), missing labels on multiple landmarks of the same type, and redundant ARIA on native elements (role="banner" on <header>, role="main" on <main>). For each finding, the remediation engine produces a concrete before / after snippet rather than a generic “add landmark here” nudge.
What we cannot decide for you is whether the landmarks you have shipped match the page intent. A page can pass every automated landmark rule and still confuse a screen-reader user because the “main” region wraps only one of two equally important content columns, or the “complementary” aside is in fact the page's primary call to action. That is a manual-review judgement call — the same kind covered in our manual checklist. For the bigger compliance picture, our WCAG 2.2 checklist covers Success Criterion 1.3.1 Info and Relationships, which is the criterion landmarks satisfy. React-specific landmark patterns (where layout components render the outer <main> and page components render the inner content) are covered in our accessible React guide, and how landmarks combine with the dialog role inside modal overlays is in our accessible modals guide.
To see what SweepHound flags on your own pages, run a free scan. The free tier covers a single site with landmark checks included; paid plans add scheduled re-scans, authenticated scanning, statement generation, and CSV/PDF export — see pricing for the breakdown. If you have not run a scan yet, start here and you will have a landmark report in under a minute.
Sources
- W3C ARIA Authoring Practices — Landmark Regions — Primary reference. Defines each landmark, when to use it, labelling rules, and the structure conventions this guide follows.
- MDN — ARIA Roles reference — Per-role reference for banner, navigation, main, complementary, contentinfo, and search — including native-element equivalences.
- Scott O’Hara — Landmarks: Use them. Or don’t. — Practitioner take on landmark over-use, duplication, and when native HTML beats explicit ARIA.
- WebAIM — Designing for Screen Reader Compatibility — Cited for screen-reader landmark navigation patterns across NVDA, JAWS, and VoiceOver.
- Deque — Automated Accessibility Coverage Report — Per Deque's Automated Accessibility Coverage Report, automated tests identified 57.38% of issue instances by volume in its dataset — based on 2,000+ audits across 13,000+ pages and ~300K issues. A share of issue volume, not a share of WCAG criteria automation can fully verify.