Landmark Elements and Heading Hierarchy
The Invisible Navigation Layer
Sighted users scan a page visually. They see the logo up top, the sidebar on the left, the main content in the center. Their eyes jump from heading to heading, skimming until something catches their attention.
Screen reader users do the exact same thing — but instead of visual layout, they rely on landmark regions and heading hierarchy. These two systems form an invisible navigation layer baked into your HTML. When you get them right, a screen reader user can jump to any section of your page in seconds. When you get them wrong, they're stuck listening to every single element from top to bottom, linearly, with no way to skip ahead.
Here's the thing most developers miss: landmarks and headings aren't just "accessibility features." They're the structural backbone of a well-built page. If your landmarks are wrong, your page structure is wrong. Period.
Think of a web page as a building. Landmark regions are the rooms — lobby, offices, kitchen, storage. Headings are the signs on the doors and the directory in the lobby that tell you what's inside each room. A sighted person walks through and reads the signs. A screen reader user pulls up the building directory (the landmarks list or headings list) and teleports directly to the room they want. If you forget to label the rooms or put wrong signs on the doors, they're wandering the hallways blind.
Landmark Regions: The Rooms of Your Page
HTML5 gave us semantic elements that double as ARIA landmark roles. Every screen reader lets users pull up a list of landmarks and jump between them instantly — think of it as a table of contents for the page structure itself.
Here are the seven landmark regions you need to know:
header / banner
The header element maps to the banner landmark role when it's a direct child of body (not nested inside article, section, or another landmark). It represents your site-wide header — the logo, primary navigation, maybe a search bar.
<body>
<header>
<!-- banner landmark: site-wide header -->
<a href="/">Logo</a>
<nav>...</nav>
</header>
</body>
One important nuance: a header inside an article or section is just a structural grouping element — it does not become a banner landmark. Only the top-level header gets that role.
nav / navigation
The nav element maps to the navigation landmark. Use it for major navigation blocks — primary nav, sidebar nav, breadcrumbs, footer links. Most pages have more than one nav, so you should label them with aria-label to distinguish them:
<nav aria-label="Primary">
<a href="/courses">Courses</a>
<a href="/blog">Blog</a>
</nav>
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/courses">Courses</a></li>
<li aria-current="page">Accessibility</li>
</ol>
</nav>
A screen reader user will see "Primary navigation" and "Breadcrumb navigation" in their landmarks list. Without those labels, they'd see "navigation" and "navigation" — useless.
main
The main element maps to the main landmark. It wraps the primary content of the page — the stuff that changes from page to page. There must be exactly one main element per page.
<body>
<header>...</header>
<main>
<!-- The primary content lives here -->
<h1>Landmark Elements and Heading Hierarchy</h1>
<article>...</article>
</main>
<footer>...</footer>
</body>
Screen reader users use the main landmark as a "skip to content" shortcut. Many screen readers let you jump directly to main with a single keystroke. If you don't have a main element, they're forced to tab through every header and nav link before reaching the actual content.
aside / complementary
The aside element maps to the complementary landmark. It represents content that is tangentially related to the main content — sidebars, related links, call-to-action panels, glossaries.
<main>
<article>
<h1>Understanding Closures</h1>
<p>...</p>
</article>
</main>
<aside aria-label="Related topics">
<h2>You might also like</h2>
<ul>
<li><a href="/scope">Scope Chains</a></li>
<li><a href="/memory">Memory Management</a></li>
</ul>
</aside>
footer / contentinfo
The footer element maps to the contentinfo landmark when it's a direct child of body. Same rule as header: a footer inside an article or section is just a structural grouping — not a landmark.
<body>
<header>...</header>
<main>...</main>
<footer>
<!-- contentinfo landmark: site-wide footer -->
<p>Copyright 2026</p>
<nav aria-label="Footer">...</nav>
</footer>
</body>
section / region
A section element only becomes a region landmark when it has an accessible name (via aria-label or aria-labelledby). Without a label, it's just a generic grouping element with no landmark role.
<!-- This IS a landmark (has aria-labelledby) -->
<section aria-labelledby="faq-heading">
<h2 id="faq-heading">Frequently Asked Questions</h2>
<p>...</p>
</section>
<!-- This is NOT a landmark (no accessible name) -->
<section>
<h2>Some Section</h2>
<p>...</p>
</section>
Use section as a landmark sparingly. Too many region landmarks clutter the landmarks list and defeat the purpose. If you have 15 labeled sections, the landmarks list becomes as useless as having none at all.
form
A form element becomes a form landmark when it has an accessible name. Same deal as section — no label, no landmark.
<!-- This IS a landmark -->
<form aria-label="Search">
<input type="search" name="q" />
<button type="submit">Search</button>
</form>
<!-- This is NOT a landmark -->
<form action="/submit">
<input type="text" name="email" />
<button type="submit">Submit</button>
</form>
The Complete Page Structure
Here's what a well-structured page looks like with all landmarks in place:
<body>
<header>
<a href="/">Logo</a>
<nav aria-label="Primary">
<a href="/courses">Courses</a>
<a href="/blog">Blog</a>
</nav>
</header>
<main>
<h1>Page Title</h1>
<article>
<h2>First Section</h2>
<p>Content...</p>
</article>
</main>
<aside aria-label="Related topics">
<h2>Related</h2>
<ul>...</ul>
</aside>
<footer>
<nav aria-label="Footer">
<a href="/privacy">Privacy</a>
<a href="/terms">Terms</a>
</nav>
<p>Copyright 2026</p>
</footer>
</body>
A screen reader user pressing a landmarks shortcut would see:
banner
navigation "Primary"
main
complementary "Related topics"
contentinfo
navigation "Footer"
Six landmarks. Clean, descriptive, instantly navigable. That's the goal.
- 1Exactly one main element per page — it is the skip-to-content target
- 2Top-level header maps to banner, top-level footer maps to contentinfo — nested ones do not
- 3Multiple nav elements need aria-label to distinguish them
- 4section and form only become landmarks when they have an accessible name
- 5Do not overuse region landmarks — too many is as bad as too few
Heading Hierarchy: The Table of Contents
If landmarks are the rooms of your building, headings are the directory that tells you what's inside each room. Screen reader users rely on heading navigation constantly — NVDA's H key jumps to the next heading, 1-6 jump to headings of a specific level. A well-structured heading hierarchy lets them skim your content exactly like a sighted user skims visually.
The Rules
Heading levels must be sequential and hierarchical. You start with h1, the main topic. Sub-sections are h2. Sub-sub-sections are h3. And so on.
<h1>JavaScript Closures</h1> <!-- The page topic -->
<h2>What Is a Closure?</h2> <!-- Major section -->
<h2>Memory Implications</h2> <!-- Another major section -->
<h3>V8's Scope Analysis</h3> <!-- Sub-section of "Memory" -->
<h3>The eval Gotcha</h3> <!-- Another sub-section -->
<h2>Common Patterns</h2> <!-- Back to major section -->
<h3>Module Pattern</h3>
<h3>Event Handlers</h3>
<h4>Debouncing</h4> <!-- Sub-sub-section -->
No Skipping Levels
This is the single most violated heading rule on the web. You must not skip from h1 to h3 or from h2 to h4. Every level must be introduced by its parent level first.
<!-- WRONG: skips from h1 to h3 -->
<h1>Page Title</h1>
<h3>Some Section</h3>
<!-- CORRECT: sequential hierarchy -->
<h1>Page Title</h1>
<h2>Some Section</h2>
Why does this matter? When a screen reader user pulls up the heading list, skipped levels create a broken outline. If they see an h3 after an h1, they'll wonder: "Is there a hidden h2 I'm missing? Did I skip a section?" It breaks their mental model of the page structure.
Exactly One h1 Per Page
Your page should have exactly one h1 that describes the primary topic. Multiple h1 elements create ambiguity — which one is the actual page title?
<!-- WRONG: two h1 elements -->
<h1>Learn Infinity</h1>
<main>
<h1>JavaScript Closures</h1>
</main>
<!-- CORRECT: one h1 for the page topic -->
<header>
<a href="/">Learn Infinity</a> <!-- Logo, not a heading -->
</header>
<main>
<h1>JavaScript Closures</h1>
</main>
Headings Are Not for Styling
This is worth hammering home: never choose a heading level based on how it looks. If you want smaller text, use CSS. The heading level communicates structure, not appearance.
<!-- WRONG: using h4 because you want smaller text -->
<h2>Main Section</h2>
<h4>I wanted this to look smaller</h4>
<!-- CORRECT: use the right level and style with CSS -->
<h2>Main Section</h2>
<h3 class="text-sm">Sub Section</h3>
Using heading tags for styling is one of the most common accessibility mistakes. It creates a broken document outline that confuses screen reader users. A screen reader does not care about font size — it cares about the heading level number. If you use h4 under h2 because you like the font size, you just told every assistive technology user that there is an invisible section between them.
How Screen Readers Use Landmarks and Headings
Understanding how people actually navigate with screen readers makes all of this click.
Landmarks Navigation
In NVDA, pressing D jumps to the next landmark. In VoiceOver on Mac, the rotor lets you browse all landmarks as a list. JAWS uses R for landmarks. The screen reader announces the landmark role and its label:
"Main landmark"
"Navigation, Primary"
"Complementary, Related topics"
"Content information"
Users jump to main to skip the header. They jump to nav to find navigation. They jump to complementary to check the sidebar. Each jump is instantaneous.
Heading Navigation
NVDA: H for next heading, Shift+H for previous. 1-6 for specific levels. VoiceOver: rotor set to "Headings" then swipe. JAWS: H key or heading level shortcuts.
A common workflow: land on the page, press 1 to find the h1 (page title), then press 2 repeatedly to scan all h2 headings (major sections). Found the section you want? Press 3 to dive into its sub-sections.
This is exactly how you'd scan a table of contents in a book. The heading hierarchy is the table of contents.
The Skip Navigation Pattern
Even with landmarks, the very first interactive element on the page matters. Best practice is to include a "skip to content" link as the first focusable element:
<body>
<a href="#main-content" class="skip-link">
Skip to main content
</a>
<header>...</header>
<main id="main-content">
<h1>Page Title</h1>
</main>
</body>
The skip link is visually hidden until focused (keyboard users pressing Tab see it appear). It lets keyboard users bypass the entire header and nav section with a single keystroke.
.skip-link {
position: absolute;
left: -9999px;
top: auto;
width: 1px;
height: 1px;
overflow: hidden;
}
.skip-link:focus {
position: fixed;
top: 0;
left: 0;
width: auto;
height: auto;
padding: 1rem;
background: var(--color-bg);
color: var(--color-text);
z-index: 9999;
}
Common Page Structure Patterns
Blog or Article Page
<body>
<a href="#content" class="skip-link">Skip to content</a>
<header>
<a href="/">Site Name</a>
<nav aria-label="Primary">...</nav>
</header>
<main id="content">
<article>
<h1>Article Title</h1>
<p>Published on January 15, 2026</p>
<h2>Introduction</h2>
<p>...</p>
<h2>Main Argument</h2>
<p>...</p>
<h3>Supporting Evidence</h3>
<p>...</p>
<h2>Conclusion</h2>
<p>...</p>
</article>
</main>
<aside aria-label="Related articles">
<h2>Related Articles</h2>
<ul>...</ul>
</aside>
<footer>
<nav aria-label="Footer">...</nav>
<p>Copyright 2026</p>
</footer>
</body>
Dashboard Page
<body>
<a href="#dashboard" class="skip-link">Skip to dashboard</a>
<header>
<a href="/">App Logo</a>
<nav aria-label="Primary">...</nav>
<form aria-label="Search">
<input type="search" />
</form>
</header>
<nav aria-label="Sidebar">
<ul>
<li><a href="/overview">Overview</a></li>
<li><a href="/courses">Courses</a></li>
<li><a href="/progress">Progress</a></li>
</ul>
</nav>
<main id="dashboard">
<h1>Dashboard</h1>
<section aria-labelledby="stats-heading">
<h2 id="stats-heading">Your Stats</h2>
<div>...</div>
</section>
<section aria-labelledby="recent-heading">
<h2 id="recent-heading">Recent Activity</h2>
<ul>...</ul>
</section>
</main>
<footer>
<p>Copyright 2026</p>
</footer>
</body>
Notice how the dashboard uses labeled section elements inside main to create sub-landmarks. A screen reader user can jump directly to "Your Stats" or "Recent Activity" from the landmarks list. This is the right use of section as a landmark — a few key areas within the main content, each with a clear label.
The ARIA Landmark Roles (When You Need Them)
In most cases, you should use the semantic HTML elements rather than ARIA roles. But there are situations where ARIA roles are necessary:
<!-- Use semantic HTML (preferred) -->
<header>...</header>
<nav>...</nav>
<main>...</main>
<!-- Use ARIA roles when you cannot use semantic elements -->
<div role="banner">...</div>
<div role="navigation" aria-label="Primary">...</div>
<div role="main">...</div>
When would you use ARIA roles instead of semantic elements? Almost never in new code. The main case is legacy codebases where changing the HTML elements would break existing CSS or JavaScript that relies on the element types. In new projects, always use the semantic elements.
The mapping between HTML elements and ARIA landmark roles is defined in the HTML Accessibility API Mappings spec. Here's the complete mapping:
header(top-level) →role="banner"nav→role="navigation"main→role="main"aside→role="complementary"footer(top-level) →role="contentinfo"section(with accessible name) →role="region"form(with accessible name) →role="form"
When you use semantic HTML elements, the browser automatically exposes the correct ARIA role to assistive technology. Adding role="banner" to a header element is redundant — the browser already does this. Adding it to a div is how you polyfill landmarks in legacy markup.
One subtle detail: header and footer only map to banner and contentinfo when they are not descendants of article, aside, main, nav, or section. Nested inside those elements, they become generic grouping elements with no landmark role. This catches many developers off guard.
Testing Your Landmark Structure
You can inspect your page's landmark structure right now. Here are the fastest ways:
Browser DevTools: In Chrome, open DevTools, go to the Accessibility tab, and check the accessibility tree. Each landmark is clearly labeled.
Screen Reader: Fire up VoiceOver (Mac: Cmd+F5) or NVDA (Windows), navigate to your page, and open the landmarks list. This is the ground truth — what the user actually experiences.
Automated tools: axe-core, Lighthouse accessibility audit, and WAVE all flag missing landmarks, skipped heading levels, and multiple h1 elements.
Quick mental check: Can you describe your page structure using only landmark names and heading levels? If the answer reads like a clean table of contents, you're in good shape. If it's confusing or has gaps, fix the HTML.
| What developers do | What they should do |
|---|---|
| Using div elements for everything and relying on visual styling to convey structure Visual styling is invisible to screen readers. Without semantic landmarks, assistive technology users have no way to navigate the page structure. They experience your page as a flat, unstructured wall of content. | Using semantic HTML elements (header, nav, main, aside, footer) that map to ARIA landmarks |
| Skipping heading levels, such as jumping from h1 directly to h3 Skipped heading levels break the document outline. Screen reader users scanning by heading level will miss content or think sections are missing. The heading hierarchy must read like a properly indented table of contents. | Using sequential heading levels: h1 then h2 then h3, never skipping |
| Using multiple h1 elements on a single page Multiple h1 elements create ambiguity about what the page is actually about. Screen reader users pressing 1 to jump to the h1 expect to land on the page title, not one of several competing headings. | Using exactly one h1 for the page title, with h2 elements for major sections |
| Choosing heading levels based on desired font size Heading levels communicate hierarchy to assistive technology. Using h4 because you want small text tells screen readers there are invisible h2 and h3 sections they cannot find. Use the correct level and apply CSS classes for visual sizing. | Choosing heading levels based on document structure, then styling with CSS |
| Having multiple nav elements without aria-label attributes Without labels, screen reader users see multiple identical 'navigation' landmarks with no way to tell them apart. Labels make each nav instantly identifiable in the landmarks list. | Labeling each nav with a descriptive aria-label like 'Primary' or 'Breadcrumb' |
- 1Heading levels must be sequential — never skip from h1 to h3 or h2 to h4
- 2Exactly one h1 per page that describes the primary page topic
- 3Choose heading levels for structure, not for font size — use CSS for visual styling
- 4Label multiple nav elements with aria-label to distinguish them in the landmarks list
- 5Use semantic HTML elements over ARIA roles whenever possible — the browser handles the mapping
- 6Test with an actual screen reader, not just automated tools — the landmarks list is the ground truth