Semantic <nav> landmarks, unique labels, current-page indicators, and an accessible mobile hamburger — in Vanilla and React.
WCAG: 1.3.1 · 2.4.1 · 2.4.5 · 3.2.3 · 4.1.2
Level: Intermediate
Icons: lucide-react
1
What we are building
A navigation that works for keyboard, screen-reader, voice and touch users — on desktop and mobile.
What we are building
Navigation is one of the most heavily-used landmarks on your site. Screen reader users navigate by landmark, so your<nav> must be semantic, uniquely labeled when you have more than one, mark the current page with aria-current, and — on mobile — expose state througharia-expanded rather than visual-only cues.
2
The 4 real-world variants
Switch between the inaccessible version and the accessible fix.
The 4 real-world variants
Variant A
Landmark + aria-current
Preferred
Live example
Click a link — aria-current="page"moves to it. SR says “current page”.
HTML · Accessible
<!-- Real <nav> landmark, real links, aria-current for the current page -->
<nav aria-label="Main">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/pricing" aria-current="page">Pricing</a></li>
<li><a href="/docs">Docs</a></li>
</ul>
</nav>
Real <nav> landmark + real anchors + aria-current='page'. The screen-reader equivalent of a highlighted menu item.
Variant B
Multiple navs on a page
Label each one
Live example
Three navigation landmarks — each labeled uniquely so the SR landmarks list is useful.
HTML · Accessible
<!-- Each nav gets a unique accessible name -->
<nav aria-label="Main">
<ul>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
</ul>
</nav>
<nav aria-label="Breadcrumb">
<ol>
<li><a href="/">Home</a></li>
<li><a href="/products">Products</a></li>
<li aria-current="page">Headphones</li>
</ol>
</nav>
<nav aria-label="Footer">
<ul>
<li><a href="/privacy">Privacy</a></li>
<li><a href="/terms">Terms</a></li>
</ul>
</nav>
If you have more than one <nav> on a page, give each a unique aria-label. 'Main', 'Breadcrumb', 'Footer' are common.
Variant C
Current page / step indicator
Preferred
Live example
Click a step to change the current one. SR announces “current step”.
HTML · Accessible
<!-- aria-current carries the state programmatically.
Visual + ARIA + text if needed. -->
<a href="/pricing" aria-current="page" class="active">
Pricing
</a>
<!-- In a stepper / wizard -->
<ol>
<li><a href="/step/1">Account</a></li>
<li><a href="/step/2">Shipping</a></li>
<li><a href="/step/3" aria-current="step">Payment</a></li>
<li><a href="/step/4">Review</a></li>
</ol>
aria-current values: page, step, location, date, true. Pair with a visual indicator — never rely on either alone.
Variant D
Mobile hamburger
Common UI
Live example
MySite
Click the hamburger — Esc closes it and returns focus to the trigger.