Use navigation landmark regions
Page navigation uses nav elements with proper ARIA labels to distinguish multiple navigation regions.
- 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
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.
Navigation Landmark Types
| Region | Element | aria-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>
)
}Skip Links
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
- Use screen reader landmark navigation (NVDA: D key, VoiceOver: rotor)
- Verify each nav region has unique label
- Check skip link appears on focus
- Verify aria-current on current page link
- Test keyboard navigation through all links
- Confirm nav count matches expected regions
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.