CANON · Navigation
Navigation is a promise: where am I, where can I go, how do I get back. Break any of the three and the user is lost.
Structural rules
Every page must answer three questions visually and semantically:
- Where am I? — active state in the nav, breadcrumb or page title
- Where else can I go? — primary nav visible or reachable in one tap
- How do I go back? — browser back always works; "back" actions never leave them stranded
Top bar vs sidebar
| Pattern |
Use when |
Don't use when |
| Top bar |
≤ 7 top-level sections, marketing, simple apps |
> 7 sections, deep hierarchies |
| Sidebar |
Apps with 8+ sections or nested nav, dashboards |
Marketing pages, content-heavy reads |
| Hybrid (top + left) |
Product with global sections + workspace nav |
Simple apps — overkill |
| Bottom tab bar (mobile) |
Apps with 3–5 primary sections |
Web-first experiences, > 5 sections |
Active state — not optional
Every nav item has two states at minimum: default and active. "Active" means "you are here." It must be unmistakable at a glance.
Active state options, in order of clarity:
- Filled background + contrasting text
- Left or bottom border in brand color (2–3px)
- Bolder weight + color shift
- Underline (text nav only)
Color shift alone is not enough — fails for color-blind users. Pair color with weight, underline, or background.
Sizing
| Element |
Dimension |
| Top bar height |
56–72px (64px is the sweet spot) |
| Sidebar width (expanded) |
220–280px |
| Sidebar width (collapsed icon-rail) |
56–72px |
| Nav item height (desktop) |
36–44px |
| Nav item height (mobile, tap target) |
≥ 44px |
| Nav item horizontal padding |
12–16px |
| Gap between items |
2–4px (stack), 16–24px (horizontal) |
| Bottom tab bar height |
56px + safe-area-inset-bottom |
Mobile menu (hamburger)
Hamburger is acceptable but comes with costs. Known: 30–50% lower discoverability vs visible nav (Luke Wroblewski research).
When hamburger is fine:
- Secondary nav items only (primary nav stays visible via tab bar or top bar)
- Settings and account sections
- Truly space-constrained
When hamburger fails:
- Hiding the only path to primary actions
- Content-heavy apps where users need to jump between sections often
Better alternatives on mobile:
- Bottom tab bar for 3–5 primary destinations
- Visible top bar with overflow menu for extras
Breadcrumbs
Home / Products / Electronics / Laptops / ThinkPad X1
Breadcrumbs are for hierarchical depth ≥ 3 levels. At 2 levels, they're noise.
- Use
<nav aria-label="Breadcrumb"> wrapping an <ol>.
- Current page is the last item;
aria-current="page" and not a link.
- Separator is decorative;
aria-hidden="true".
Skip link — required
<a href="#main" class="skip-link">Skip to main content</a>
- First focusable element on every page.
- Visually hidden until focused (
:focus reveals it).
- Jumps keyboard users past the nav to the content.
- WCAG 2.4.1 Bypass Blocks.
Semantic structure
<header>
<a href="/" aria-label="Home">...</a>
<nav aria-label="Primary">
<ul>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
</header>
<main id="main">...</main>
<footer>
<nav aria-label="Footer">...</nav>
</footer>
- Multiple
<nav> elements allowed. Each needs a unique aria-label.
- Lists (
<ul>) are the correct structure for nav items.
<header> and <footer> at the page level; section-level headers don't need nav roles.
Keyboard behavior
| Key |
Behavior |
| Tab |
Move through top-level nav items |
| Shift+Tab |
Reverse |
| Enter / Space |
Activate link/button |
| Arrow keys |
Within a menu or menubar — WAI-ARIA disclosure/menu pattern |
| Escape |
Close open submenu |
For dropdown menus: use the WAI-ARIA menu or disclosure pattern, pick one, implement it fully.
Submenus and dropdowns
- Open on click, not hover. Hover menus break on touch and trap keyboard users.
- If hover is used for discoverability, still work on click, still work with keyboard.
- Submenus open toward the viewport center, not the edge.
- Close on: Escape, click outside, focus leaves.
Active state indicator math
Active color needs 3:1 contrast against the nav background — that's the WCAG 1.4.11 non-text contrast floor. A bottom-border at 2px wins against a dim tint at 1.5:1.
Anti-patterns
| Anti-pattern |
Why it fails |
| No active state |
Users can't tell where they are |
| Active state is color-only |
Fails for color-blind users |
| Hamburger hiding primary nav on desktop |
Wastes screen real estate, lowers discovery |
| Nav items ≥ 8 deep in a top bar |
Visual clutter, sidebar is better |
| Hover-only dropdowns |
Broken on touch + keyboard |
| No skip link |
WCAG 2.4.1 fail |
| Sticky nav taking > 20% of viewport height |
Eats content on mobile |
| Breadcrumbs at depth 1 or 2 |
Visual noise |
Logo without aria-label when it's the home link |
Screen reader says "link" with no context |
Nav inside a <div> instead of <nav> |
Semantic fail |
Decision tree
How many primary destinations?
├─ 3–5 mobile, 5–7 desktop → Top bar or tab bar
├─ 8–15 → Sidebar
└─ > 15 → Sidebar with grouping / sections
Is there nested hierarchy?
├─ Yes → Breadcrumb + sidebar
└─ No → Top bar is fine
Is the menu opening dropdowns?
└─ Click-to-open, not hover. Always.
Hamburger menu on desktop?
└─ Almost never. Only if space is genuinely exhausted.
Audit checklist
Sources
- WCAG 2.2 · 2.4.1 Bypass Blocks, 2.4.3 Focus Order, 2.4.7 Focus Visible, 1.4.11 Non-Text Contrast
- WAI-ARIA Authoring Practices · Menubar, Disclosure, Breadcrumb
- Luke Wroblewski · Obvious Always Wins (hamburger research)
- Apple HIG · Navigation Bars, Tab Bars
- Material Design 3 · Navigation bar, Navigation rail, Navigation drawer
1---2name: canon-navigation3description: Use when designing, auditing, or refactoring navigation — top bars, sidebars, breadcrumbs, footer nav, mobile menus, tab bars, or any way-finding element. Covers information architecture, active state, keyboard navigation, skip links, mobile patterns, and the sidebar vs top-bar decision. Trigger when the user mentions nav, navbar, sidebar, menu, breadcrumb, hamburger, or header.4---56# CANON · Navigation78Navigation is a promise: where am I, where can I go, how do I get back. Break any of the three and the user is lost.910## Structural rules1112Every page must answer three questions visually and semantically:13141. **Where am I?** — active state in the nav, breadcrumb or page title152. **Where else can I go?** — primary nav visible or reachable in one tap163. **How do I go back?** — browser back always works; "back" actions never leave them stranded1718## Top bar vs sidebar1920| Pattern | Use when | Don't use when |21|---|---|---|22| Top bar | ≤ 7 top-level sections, marketing, simple apps | > 7 sections, deep hierarchies |23| Sidebar | Apps with 8+ sections or nested nav, dashboards | Marketing pages, content-heavy reads |24| Hybrid (top + left) | Product with global sections + workspace nav | Simple apps — overkill |25| Bottom tab bar (mobile) | Apps with 3–5 primary sections | Web-first experiences, > 5 sections |2627## Active state — not optional2829Every nav item has two states at minimum: **default** and **active**. "Active" means "you are here." It must be **unmistakable at a glance**.3031Active state options, in order of clarity:321. Filled background + contrasting text332. Left or bottom border in brand color (2–3px)343. Bolder weight + color shift354. Underline (text nav only)3637**Color shift alone is not enough** — fails for color-blind users. Pair color with weight, underline, or background.3839## Sizing4041| Element | Dimension |42|---|---|43| Top bar height | 56–72px (64px is the sweet spot) |44| Sidebar width (expanded) | 220–280px |45| Sidebar width (collapsed icon-rail) | 56–72px |46| Nav item height (desktop) | 36–44px |47| Nav item height (mobile, tap target) | ≥ 44px |48| Nav item horizontal padding | 12–16px |49| Gap between items | 2–4px (stack), 16–24px (horizontal) |50| Bottom tab bar height | 56px + safe-area-inset-bottom |5152## Mobile menu (hamburger)5354Hamburger is acceptable but comes with costs. Known: 30–50% lower discoverability vs visible nav (Luke Wroblewski research).5556When hamburger is fine:57- Secondary nav items only (primary nav stays visible via tab bar or top bar)58- Settings and account sections59- Truly space-constrained6061When hamburger fails:62- Hiding the only path to primary actions63- Content-heavy apps where users need to jump between sections often6465Better alternatives on mobile:66- Bottom tab bar for 3–5 primary destinations67- Visible top bar with overflow menu for extras6869## Breadcrumbs7071```72Home / Products / Electronics / Laptops / ThinkPad X173```7475Breadcrumbs are for hierarchical depth ≥ 3 levels. At 2 levels, they're noise.7677- Use `<nav aria-label="Breadcrumb">` wrapping an `<ol>`.78- Current page is the last item; `aria-current="page"` and not a link.79- Separator is decorative; `aria-hidden="true"`.8081## Skip link — required8283```html84<a href="#main" class="skip-link">Skip to main content</a>85```8687- First focusable element on every page.88- Visually hidden until focused (`:focus` reveals it).89- Jumps keyboard users past the nav to the content.90- WCAG 2.4.1 Bypass Blocks.9192## Semantic structure9394```html95<header>96 <a href="/" aria-label="Home">...</a>97 <nav aria-label="Primary">98 <ul>99 <li><a href="/products">Products</a></li>100 <li><a href="/about">About</a></li>101 </ul>102 </nav>103</header>104105<main id="main">...</main>106107<footer>108 <nav aria-label="Footer">...</nav>109</footer>110```111112- Multiple `<nav>` elements allowed. Each needs a unique `aria-label`.113- Lists (`<ul>`) are the correct structure for nav items.114- `<header>` and `<footer>` at the page level; section-level headers don't need nav roles.115116## Keyboard behavior117118| Key | Behavior |119|---|---|120| Tab | Move through top-level nav items |121| Shift+Tab | Reverse |122| Enter / Space | Activate link/button |123| Arrow keys | Within a menu or menubar — WAI-ARIA disclosure/menu pattern |124| Escape | Close open submenu |125126For dropdown menus: use the WAI-ARIA menu or disclosure pattern, pick one, implement it fully.127128## Submenus and dropdowns129130- **Open on click, not hover.** Hover menus break on touch and trap keyboard users.131- If hover is used for discoverability, still work on click, still work with keyboard.132- Submenus open toward the viewport center, not the edge.133- Close on: Escape, click outside, focus leaves.134135## Active state indicator math136137Active color needs 3:1 contrast against the nav background — that's the WCAG 1.4.11 non-text contrast floor. A bottom-border at 2px wins against a dim tint at 1.5:1.138139## Anti-patterns140141| Anti-pattern | Why it fails |142|---|---|143| No active state | Users can't tell where they are |144| Active state is color-only | Fails for color-blind users |145| Hamburger hiding primary nav on desktop | Wastes screen real estate, lowers discovery |146| Nav items ≥ 8 deep in a top bar | Visual clutter, sidebar is better |147| Hover-only dropdowns | Broken on touch + keyboard |148| No skip link | WCAG 2.4.1 fail |149| Sticky nav taking > 20% of viewport height | Eats content on mobile |150| Breadcrumbs at depth 1 or 2 | Visual noise |151| Logo without `aria-label` when it's the home link | Screen reader says "link" with no context |152| Nav inside a `<div>` instead of `<nav>` | Semantic fail |153154## Decision tree155156```157How many primary destinations?158 ├─ 3–5 mobile, 5–7 desktop → Top bar or tab bar159 ├─ 8–15 → Sidebar160 └─ > 15 → Sidebar with grouping / sections161162Is there nested hierarchy?163 ├─ Yes → Breadcrumb + sidebar164 └─ No → Top bar is fine165166Is the menu opening dropdowns?167 └─ Click-to-open, not hover. Always.168169Hamburger menu on desktop?170 └─ Almost never. Only if space is genuinely exhausted.171```172173## Audit checklist174175- [ ] Active state visible without relying on color alone176- [ ] Skip link is the first focusable element177- [ ] Nav is `<nav>` with `aria-label`178- [ ] Each `<nav>` has a unique label179- [ ] Tab target ≥ 44px on mobile180- [ ] Dropdowns open on click and work with keyboard181- [ ] Escape closes menus182- [ ] Focus-visible on every nav item183- [ ] Breadcrumb uses `aria-current="page"` on last item184- [ ] No nav inside `<div>` when `<nav>` applies185186## Sources187188- WCAG 2.2 · 2.4.1 Bypass Blocks, 2.4.3 Focus Order, 2.4.7 Focus Visible, 1.4.11 Non-Text Contrast189- WAI-ARIA Authoring Practices · Menubar, Disclosure, Breadcrumb190- Luke Wroblewski · Obvious Always Wins (hamburger research)191- Apple HIG · Navigation Bars, Tab Bars192- Material Design 3 · Navigation bar, Navigation rail, Navigation drawer