Skip to main content
Beta: Front-End Checklist is currently in beta. Some issues are still being fixed. Thanks for your patience.

Use navigation landmark regions

Page navigation uses nav elements with proper ARIA labels to distinguish multiple navigation regions.

Utilities
Quick take
Typical fix time 15 min
  • Wrap navigation links in nav elements
  • Use aria-label to distinguish multiple nav regions
  • Provide skip links to bypass repetitive navigation
  • Screen reader users navigate by landmarks
Why it matters: Navigation landmarks allow screen reader users to quickly jump to and identify different navigation areas—without them, users must tab through every link to find what they need.

Rule Details

Navigation landmarks help users understand page structure and quickly jump to different navigation sections.

Code Example

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Page Title</title>
</head>
<body>
  <!-- Skip link (first element) -->
  <a href="#main-content" class="skip-link">
    Skip to main content
  </a>
 
  <header>
    <!-- Primary navigation -->
    <nav aria-label="Main">
      <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/products">Products</a></li>
        <li><a href="/about">About</a></li>
        <li><a href="/contact">Contact</a></li>
      </ul>
    </nav>
  </header>
 
  <!-- Breadcrumb navigation -->
  <nav aria-label="Breadcrumb">
    <ol>
      <li><a href="/">Home</a></li>
      <li><a href="/products">Products</a></li>
      <li><a href="/products/widgets" aria-current="page">Widgets</a></li>
    </ol>
  </nav>
 
  <main id="main-content">
    <!-- Page content -->
 
    <!-- In-page navigation (table of contents) -->
    <nav aria-label="Table of contents">
      <h2>On this page</h2>
      <ul>
        <li><a href="#section-1">Section 1</a></li>
        <li><a href="#section-2">Section 2</a></li>
        <li><a href="#section-3">Section 3</a></li>
      </ul>
    </nav>
 
    <h1>Page Title</h1>
    <section id="section-1">...</section>
    <section id="section-2">...</section>
    <section id="section-3">...</section>
  </main>
 
  <aside>
    <!-- Sidebar navigation -->
    <nav aria-label="Related pages">
      <h2>Related</h2>
      <ul>
        <li><a href="/related-1">Related Page 1</a></li>
        <li><a href="/related-2">Related Page 2</a></li>
      </ul>
    </nav>
  </aside>
 
  <footer>
    <!-- Footer navigation -->
    <nav aria-label="Footer">
      <ul>
        <li><a href="/privacy">Privacy Policy</a></li>
        <li><a href="/terms">Terms of Service</a></li>
        <li><a href="/sitemap">Sitemap</a></li>
      </ul>
    </nav>
  </footer>
</body>
</html>

Why It Matters

Navigation landmarks allow screen reader users to quickly jump to and identify different navigation areas—without them, users must tab through every link to find what they need.

RegionElementaria-label Example
Main navigation<nav>"Main navigation"
Secondary navigation<nav>"Secondary navigation"
Footer navigation<nav>"Footer navigation"
Breadcrumb<nav>"Breadcrumb"
Pagination<nav>"Pagination"
Table of contents<nav>"Table of contents"

React Navigation Components

interface NavLinkProps {
  href: string
  children: React.ReactNode
  isCurrent?: boolean
}
 
function NavLink({ href, children, isCurrent }: NavLinkProps) {
  return (
    <li>
      <a
        href={href}
        aria-current={isCurrent ? 'page' : undefined}
      >
        {children}
      </a>
    </li>
  )
}
 
interface MainNavProps {
  links: Array<{ href: string; label: string }>
  currentPath: string
}
 
export function MainNav({ links, currentPath }: MainNavProps) {
  return (
    <nav aria-label="Main">
      <ul className="main-nav">
        {links.map(link => (
          <NavLink
            key={link.href}
            href={link.href}
            isCurrent={currentPath === link.href}
          >
            {link.label}
          </NavLink>
        ))}
      </ul>
    </nav>
  )
}
 
interface BreadcrumbProps {
  items: Array<{ href: string; label: string }>
}
 
export function Breadcrumb({ items }: BreadcrumbProps) {
  return (
    <nav aria-label="Breadcrumb">
      <ol className="breadcrumb">
        {items.map((item, index) => {
          const isLast = index === items.length - 1
          return (
            <li key={item.href}>
              {isLast ? (
                <span aria-current="page">{item.label}</span>
              ) : (
                <>
                  <a href={item.href}>{item.label}</a>
                  <span aria-hidden="true"> / </span>
                </>
              )}
            </li>
          )
        })}
      </ol>
    </nav>
  )
}
 
interface FooterNavProps {
  sections: Array<{
    title: string
    links: Array<{ href: string; label: string }>
  }>
}
 
export function FooterNav({ sections }: FooterNavProps) {
  return (
    <nav aria-label="Footer">
      <div className="footer-nav">
        {sections.map(section => (
          <div key={section.title} className="footer-nav__section">
            <h3>{section.title}</h3>
            <ul>
              {section.links.map(link => (
                <li key={link.href}>
                  <a href={link.href}>{link.label}</a>
                </li>
              ))}
            </ul>
          </div>
        ))}
      </div>
    </nav>
  )
}
export function SkipLinks() {
  return (
    <div className="skip-links">
      <a href="#main-content" className="skip-link">
        Skip to main content
      </a>
      <a href="#main-nav" className="skip-link">
        Skip to navigation
      </a>
      <a href="#search" className="skip-link">
        Skip to search
      </a>
    </div>
  )
}
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px 16px;
  background: #000;
  color: #fff;
  z-index: 1000;
  transition: top 0.2s;
}
 
.skip-link:focus {
  top: 0;
}

Next.js Layout Example

// app/layout.tsx
import { MainNav } from '@/components/MainNav'
import { FooterNav } from '@/components/FooterNav'
import { SkipLinks } from '@/components/SkipLinks'
 
export default function RootLayout({
  children
}: {
  children: React.ReactNode
}) {
  const navLinks = [
    { href: '/', label: 'Home' },
    { href: '/products', label: 'Products' },
    { href: '/about', label: 'About' },
    { href: '/contact', label: 'Contact' },
  ]
 
  const footerSections = [
    {
      title: 'Company',
      links: [
        { href: '/about', label: 'About Us' },
        { href: '/careers', label: 'Careers' },
      ]
    },
    {
      title: 'Legal',
      links: [
        { href: '/privacy', label: 'Privacy Policy' },
        { href: '/terms', label: 'Terms of Service' },
      ]
    }
  ]
 
  return (
    <html lang="en">
      <body>
        <SkipLinks />
 
        <header>
          <MainNav links={navLinks} currentPath="/" />
        </header>
 
        <main id="main-content">
          {children}
        </main>
 
        <footer>
          <FooterNav sections={footerSections} />
        </footer>
      </body>
    </html>
  )
}

When to Use aria-labelledby vs aria-label

<!-- aria-label: Short, simple label -->
<nav aria-label="Main">
  <!-- No visible heading -->
</nav>
 
<!-- aria-labelledby: Reference visible heading -->
<nav aria-labelledby="footer-nav-heading">
  <h2 id="footer-nav-heading">Quick Links</h2>
  <ul>...</ul>
</nav>

Common Mistakes

<!-- ❌ Multiple nav without labels -->
<nav>...</nav>
<nav>...</nav>
 
<!-- ✓ Labeled navigation regions -->
<nav aria-label="Main">...</nav>
<nav aria-label="Footer">...</nav>
 
<!-- ❌ Using div instead of nav -->
<div class="navigation">...</div>
 
<!-- ✓ Semantic nav element -->
<nav aria-label="Main">...</nav>
 
<!-- ❌ Nesting nav elements -->
<nav>
  <nav>...</nav>
</nav>
 
<!-- ✓ Separate nav regions -->
<nav aria-label="Primary">...</nav>
<nav aria-label="Secondary">...</nav>

Verification

  1. Use screen reader landmark navigation (NVDA: D key, VoiceOver: rotor)
  2. Verify each nav region has unique label
  3. Check skip link appears on focus
  4. Verify aria-current on current page link
  5. Test keyboard navigation through all links
  6. Confirm nav count matches expected regions
Don't Overuse Navigation Landmarks

Use nav elements only for major navigation blocks. Minor link groups (like social media icons) don't need to be navigation landmarks. Too many landmarks reduces their usefulness.

Use with AI

Copy these prompts to use with your AI assistant, or install the MCP server to use directly from Claude, Cursor, or Windsurf.

Check

Verify implementation

Verify navigation areas use nav elements with aria-label or aria-labelledby to distinguish primary, secondary, and footer navigation.

Fix

Auto-fix issues

Wrap navigation links in nav elements with descriptive aria-labels like 'Main navigation' or 'Footer navigation'.

Explain

Learn more

Explain how navigation landmarks help screen reader users quickly identify and jump to different navigation areas.

Review

Code review

Review templates, server-rendered HTML, and shared components that output markup related to Use navigation landmark regions. Flag exact elements, attributes, and routes where the rendered HTML violates the rule.

Sources

References used to support the guidance in this rule.

Further Reading

Tools and supplementary material for exploring the topic in more depth.

Nu Html Checker
validator.w3.orgTool

Rules that often go hand-in-hand with this one.

Create a custom 404 error page

A custom 404 error page is designed with helpful navigation options for lost users.

HTML
Make pagination accessible

Pagination controls are accessible with proper ARIA labels, keyboard navigation, and current page indication.

HTML
Ensure tables have unique accessible names

Checks that data tables have unique accessible names

Accessibility
Use landmark regions correctly

Proper landmark regions (main, nav, footer) help users navigate the page more efficiently.

Accessibility

Was this rule helpful?

Your feedback helps improve rule quality. This stays internal for now.

Loading feedback...
0 / 385