PushBackLog

ARIA Landmarks

Advisory enforcement Complete by PushBackLog team
Topic: accessibility Topic: quality Skillset: frontend Technology: HTML Stage: execution Stage: review

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 main content 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 roleHTML equivalentPrefer
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.



Part of the PushBackLog Best Practices Library. Suggest improvements →