ARIA Landmarks
Status: Complete
Category: Accessibility
Default enforcement: Advisory
Author: PushBackLog team
Tags
- Topic: accessibility, quality
- Skillset: frontend
- Technology: HTML
- Stage: execution, review
Summary
ARIA (Accessible Rich Internet Applications) landmark roles identify the major structural regions of a page — banner, navigation, main, complementary, contentinfo — enabling screen reader users to skip directly to the section they need. Used correctly, landmarks dramatically improve navigation for non-visual users. Used incorrectly, they create confusion and redundancy.
Rationale
The navigation problem ARIA landmarks solve
A sighted user scanning a page instantly perceives the header, the navigation bar, the main content area, and the footer as distinct regions. A screen reader user listening to the page linearly — especially a long page — has no equivalent quick overview unless the page exposes structural landmarks.
ARIA landmarks allow screen reader users to:
- List all landmarks on the page and jump directly to any one
- Skip past the header and navigation to the
maincontent with a single keystroke - Navigate between sections without reading every element
This is one of the most impactful accessibility improvements because it saves navigation time on every page visit.
First rule of ARIA: prefer semantic HTML
The W3C’s first rule of ARIA use is: “If you can use a native HTML element or attribute with the semantics and behaviour you require already built in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, then do so.”
Most landmark roles have HTML element equivalents:
| ARIA role | HTML equivalent | Prefer |
|---|---|---|
role="banner" | <header> (when top-level) | <header> |
role="navigation" | <nav> | <nav> |
role="main" | <main> | <main> |
role="complementary" | <aside> | <aside> |
role="contentinfo" | <footer> (when top-level) | <footer> |
role="search" | <search> (HTML5.3) | <search> or role="search" on a <form> |
role="region" | <section> (with accessible name) | <section aria-labelledby> |
Use ARIA roles only when semantic HTML equivalents are unavailable or the element cannot be changed (third-party components, legacy markup).
Guidance
Labelling multiple landmarks of the same type
A page with two <nav> elements must distinguish them for screen reader users who are browsing all landmarks:
<!-- Two navs must have distinct labels -->
<nav aria-label="Main navigation">
<ul>...</ul>
</nav>
<nav aria-label="Breadcrumb">
<ol>...</ol>
</nav>
<!-- Alternatively, aria-labelledby pointing to a visible heading -->
<aside aria-labelledby="related-heading">
<h2 id="related-heading">Related articles</h2>
...
</aside>
When to use role="region"
A <section> element only creates a landmark when it has an accessible name (via aria-label or aria-labelledby). Without a name, it is treated as a generic container:
<!-- Not a landmark: no accessible name -->
<section>
<p>Some content</p>
</section>
<!-- Landmark: has an accessible name -->
<section aria-labelledby="recent-heading">
<h2 id="recent-heading">Recent activity</h2>
...
</section>
Dynamic content: aria-live
For content that updates without a page reload (notifications, status messages, search results):
<!-- Announce politely (waits for current speech to finish) -->
<div aria-live="polite" aria-atomic="true">
{statusMessage}
</div>
<!-- Announce immediately (interrupts current speech) — use sparingly -->
<div role="alert">
{errorMessage}
</div>
Examples
Complete page landmark structure
<body>
<!-- role="banner" is implicit for top-level <header> -->
<header>
<a href="/"><img src="/logo.svg" alt="PushBackLog" /></a>
<nav aria-label="Main navigation">...</nav>
</header>
<!-- role="main" is implicit -->
<main>
<h1>Sprint Dashboard</h1>
<!-- Named section = "region" landmark -->
<section aria-labelledby="active-sprints">
<h2 id="active-sprints">Active sprints</h2>
...
</section>
</main>
<!-- role="complementary" is implicit for <aside> -->
<aside aria-labelledby="team-updates">
<h2 id="team-updates">Team updates</h2>
...
</aside>
<!-- role="contentinfo" is implicit for top-level <footer> -->
<footer>
<nav aria-label="Footer navigation">...</nav>
</footer>
</body>
This page exposes: banner, 2 navigation, main, region (active sprints), complementary, contentinfo — all directly jumpable from a screen reader’s landmark list.
Anti-patterns
1. Redundant ARIA on semantic elements
<!-- Redundant: <nav> already has role="navigation" -->
<nav role="navigation">...</nav>
<!-- Redundant: <main> already has role="main" -->
<main role="main">...</main>
Redundancy is harmless but clutters the markup without benefit.
2. Multiple role="main" or multiple <main> elements
A page must have exactly one main landmark. Multiple <main> elements confuse screen reader users and violate WCAG 1.3.1.
3. Using ARIA to compensate for non-semantic HTML
<!-- Wrong approach: bolting semantics onto a div -->
<div role="navigation" tabindex="-1">
<div onclick="navigate('/home')" role="link" tabindex="0">Home</div>
</div>
<!-- Right approach: fix the HTML -->
<nav><a href="/home">Home</a></nav>
4. Missing labels on multiple instances of the same role
Two <nav> elements or two <nav role="navigation"> without aria-label are indistinguishable in a landmarks list. Screen reader users hear “navigation, navigation” with no way to differentiate them.
Related practices
Part of the PushBackLog Best Practices Library. Suggest improvements →