Components

Navigation Patterns

How to structure navigation in Apple-inspired interfaces — from hierarchical push navigation to flat tab bars, sidebars, and everything in between.

Navigation Models

Apple's HIG defines three fundamental navigation structures. Choosing the right model is the single most important navigation decision — it determines how users form a mental map of your app and how they move through content.

Hierarchical
Users drill down through levels of content. Each screen shows a subset of the previous, with a back button to retrace steps. Classic iOS push navigation.
Root List
Detail View
Edit / Action
Use when: Content has a clear parent-child structure. Settings, files, messages — anywhere users drill into progressively specific information.
Flat
Peer sections at the same hierarchy level. Users switch between categories instantly with zero drilling. Implemented via tab bar or top segment control.
Home
Search
Library
Profile
← swipe or tap to switch →
Use when: Your app has 3–5 peer sections of roughly equal importance. Music, Maps, Health — areas where users frequently switch between sections.
Hub & Spoke
A central home screen (hub) launches tasks (spokes). Users complete the task then return to the hub. No direct path between spokes — always return to center first.
HUB
Task A
Task B
Task C
Use when: Tasks are independent and don't share state. Utilities, Camera Roll, App Store — apps where tasks have a clear beginning and end.
💡
Mixing models: Real apps often combine models. Mail uses hierarchical navigation within each tab of a flat tab bar. Don't be afraid to nest models — just be consistent and never surprise the user about how to get back.

Navigation Bar

The navigation bar sits at the top of the screen and provides context: where you are, where you came from (back button), and actions specific to the current screen. It transforms from a large title (on scroll up / at rest) to a compact title (on scroll down).

Standard Nav Bar — Scrolled state (compact title)
Settings
Large Title Nav Bar — Resting state (scroll up)
Accessibility
Left slot
Back button only. Never put custom actions on the left — it breaks the back gesture affordance.
Center
Current screen title. Keep it short — 1–3 words. Never truncate with ellipsis; shorten the title instead.
Right slot
Up to 3 actions max. Most common: Edit, Add (+), Share. Use icons for recognized actions, text for custom ones.

Tab Bar

The tab bar lives at the bottom of the screen on iOS, providing always-visible switching between the top-level sections of your app. On web, translate this to a persistent bottom nav (mobile) or top navigation tabs (desktop). Tab bars are flat — every item is always one tap away.

Home
Your personalized feed and activity

Click any tab to switch — try them all

Do
  • 3–5 tabs maximum
  • Show all tabs at all times
  • Use filled icon for selected, outline for unselected
  • Keep each tab's navigation stack independent
  • Show badge counts for notifications
Don't
  • More than 5 tabs (use More pattern instead)
  • Hide or disable tabs conditionally
  • Use the tab bar for context-specific actions
  • Mix icon-only and text+icon tabs in the same bar
  • Reset tab stack when user switches and returns

Sidebar

Introduced prominently on iPad and macOS, the sidebar is the definitive navigation for complex apps with many sections. On web and SaaS, the sidebar is the dominant navigation pattern — it scales to dozens of items and communicates application structure at a glance.

My App
Workspace
Dashboard
Projects
Tasks
Team
Members
Permissions
Settings
General
Billing
Anatomy of a Sidebar
Header
App logo/name + theme toggle. Sticky at top. Never scrolls away.
Search
Inline search for large navs (10+ items). Filters visible items in real time.
Labeled Sections
Group related items under ALL-CAPS labels. Max 4–5 items per group before splitting.
Active Indicator
Left-edge 3px bar + accent background tint. One active item at a time, always visible.

Push vs. Modal vs. Sheet

Choosing how to present a new screen is one of the most consequential decisions in navigation design. Each presentation style carries a specific implicit promise to the user about context, urgency, and how to dismiss.

Is the user leaving the current context?
YES
Does the user need to complete a task before returning?
YES
Modal / Full-Screen Sheet
Blocks interaction. Requires explicit completion or Cancel.
Login, payment, permissions, data entry
NO
Push Navigation
Slides in from right. Back swipe to return.
Detail views, sub-settings, drill-down content
NO
Tab Bar or Sidebar
Context switch at same level. No back button needed.
Switching between top-level app sections
Push Navigation
Slides a new screen on top of the navigation stack. The back button and edge-swipe gesture are implicit dismissals.
Dismiss: Back button or swipe from left edge
When: Drilling into related content
Modal Sheet
Slides up from the bottom (iOS) or fades in center-screen (macOS/web). Interrupts the flow intentionally. Requires an explicit Done/Cancel.
Dismiss: Done, Cancel, or swipe down
When: Task completion required before returning
Popover / Tooltip
Appears anchored to a specific UI element. Lightweight — tapping outside dismisses it. Used for contextual actions and options, not deep navigation.
Dismiss: Tap outside or Escape
When: Short-lived contextual actions only

Search Pattern

Search is a navigation shortcut — it lets users bypass the navigation hierarchy entirely. Apple's search pattern has four distinct states, each requiring specific visual treatment to communicate what's happening and what's expected next.

1 — Default
Search
Placeholder visible. Field is de-emphasized, integrated into the layout.
2 — Focused
Search
Accent ring appears. Cancel button slides in on the right. Recent searches appear below.
3 — Typing
settings
Live results appear below as user types. Clear (×) button replaces cursor. Instant — no search button needed.
4 — Results
settings
Results page replaces regular content. Query is highlighted in result text. Count shown if possible.
⚠️
Search placement: In iOS, search lives in a search bar below the large navigation bar title. On web, search belongs in the sidebar header (for site-wide search) or in the page header (for content-scoped search). Never hide it in a hamburger menu.

Navigation in Web & SaaS

Apple's native navigation patterns translate directly to web and SaaS products. Each native pattern has a well-established web equivalent — the key is preserving the underlying behavioral contract, not copying the pixel-for-pixel visual.

Pattern Native Origin Web Translation Best For Max Items
Tab Bar iOS Bottom nav (mobile) / Top tabs (desktop) Simple apps, 3–5 sections 5
Sidebar iPad / macOS Persistent left nav, collapsible on mobile Complex apps, many sections Unlimited
Navigation Bar iOS Top bar with back link + breadcrumbs Hierarchical content, admin portals 3 actions
Toolbar macOS Action bar / command bar Document & editor apps 8–10
Push Navigation iOS UINavigationController URL routing, history.pushState Any content with depth
Modal Sheet iOS / macOS sheet Dialog, drawer, slide-over panel Task flows, quick edits
Split View iPad / macOS Master-detail layout (list + content pane) Email, files, messaging

Common Mistakes

These mistakes appear repeatedly in interfaces that aren't following HIG principles. Each one creates friction or confusion — and each has a straightforward fix.

Mistake
More than 5 tabs in a tab bar
Tab bars with 6+ items become unreadable on small screens. Icons and labels are too small to parse quickly, and the bar loses its purpose as a fast-switch control.
Fix: Move to a sidebar, or use a "More" tab with a secondary list for additional sections.
Mistake
Back button without a label
An arrow-only back button removes context. Users don't know where they're going when they tap back, which causes hesitation and distrust of the navigation.
Fix: Always label the back button with the title of the previous screen. Truncate to "Back" only when the previous title is too long.
Mistake
Using modals for non-blocking content
Modals carry an implicit "you must deal with this now" message. Using them for read-only content, detail views, or anything the user doesn't need to act on creates unnecessary friction.
Fix: Use push navigation for detail views. Reserve modals exclusively for task-completion flows.
Mistake
Hiding navigation inside a hamburger menu
Hamburger menus reduce discoverability by 37% (NNG). Primary navigation that requires a tap to reveal is navigation that users won't use — they'll only navigate to sections they can see.
Fix: Use a tab bar (mobile) or persistent sidebar (desktop). Reserve hamburger for secondary or rarely-needed navigation items only.
Mistake
Resetting tab state on switch
If a user has scrolled deep into the Messages tab, switches to Settings, then returns — they expect to be exactly where they left off. Resetting the scroll position and navigation stack destroys context.
Fix: Preserve navigation stack and scroll position per tab. Only reset on explicit user action (double-tap the same tab).
Mistake
Deep-nesting push navigation
Drilling 6+ levels deep creates cognitive overload. The back stack becomes a mystery — users have no idea how many taps it will take to get home, so they abandon the flow entirely.
Fix: Restructure to 3 levels max. Flatten with inline expansion or use a sheet for deep sub-tasks. Always provide a "Home" or "Done" escape hatch.

Code: Web Navigation Components

Production-ready CSS for the three core navigation components. Each uses the design token system for colors, spacing, and blur values.

Glass Navigation Bar
CSS
/* ── Glass Navigation Bar ── */
.nav-bar {
  position: sticky;
  top: 0;
  z-index: var(--z-raised);
  height: 52px;
  padding: 0 var(--space-5);
  display: flex;
  align-items: center;
  justify-content: space-between;

  /* Liquid Glass effect */
  background: var(--color-glass);
  backdrop-filter: blur(var(--blur-regular));
  -webkit-backdrop-filter: blur(var(--blur-regular));
  border-bottom: 1px solid var(--color-border);
}

.nav-bar-title {
  font-size: 17px;
  font-weight: var(--weight-semibold);
  color: var(--color-text-primary);
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
}

.nav-bar-back {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: none;
  border: none;
  color: var(--color-accent);
  font-size: 17px;
  cursor: pointer;
  padding: var(--space-2) 0;
  transition: opacity var(--duration-fast) var(--easing-standard);
}
.nav-bar-back:hover { opacity: 0.75; }

.nav-bar-action {
  background: none;
  border: none;
  color: var(--color-accent);
  font-size: 17px;
  cursor: pointer;
  padding: var(--space-2) 0;
}

/* Large title variant */
.nav-bar.nav-bar--large {
  height: auto;
  flex-direction: column;
  align-items: stretch;
  padding: 0 var(--space-5) var(--space-4);
}

.nav-bar--large .nav-bar-row {
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.nav-bar--large .nav-bar-large-title {
  font-size: 34px;
  font-weight: var(--weight-bold);
  letter-spacing: -0.025em;
  color: var(--color-text-primary);
  margin-top: var(--space-1);
}
Tab Bar
CSS
/* ── Tab Bar ── */
.tab-bar {
  display: flex;
  justify-content: space-around;
  align-items: stretch;
  height: 49px; /* iOS standard */
  padding-bottom: env(safe-area-inset-bottom, 0px);

  background: var(--color-glass);
  backdrop-filter: blur(var(--blur-regular));
  -webkit-backdrop-filter: blur(var(--blur-regular));
  border-top: 1px solid var(--color-border);
}

/* Fixed to bottom on mobile */
@media (max-width: 768px) {
  .tab-bar {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: var(--z-raised);
  }
}

.tab-bar-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-text-tertiary);
  font-size: 10px;
  font-weight: var(--weight-medium);
  padding: var(--space-2) var(--space-4);
  transition: color var(--duration-fast) var(--easing-standard),
              transform var(--duration-fast) var(--easing-spring);
}

.tab-bar-item:hover {
  color: var(--color-text-secondary);
}

.tab-bar-item.active {
  color: var(--color-accent);
}

.tab-bar-item:active {
  transform: scale(0.92);
}

.tab-bar-item svg {
  width: 24px;
  height: 24px;
  stroke-width: 1.8;
  transition: stroke-width var(--duration-fast) var(--easing-standard);
}

/* Active: use filled icon (set stroke-width higher or swap to filled SVG) */
.tab-bar-item.active svg {
  stroke-width: 2.4;
}

/* Badge */
.tab-bar-badge {
  position: absolute;
  top: 4px;
  right: calc(50% - 20px);
  min-width: 16px;
  height: 16px;
  padding: 0 4px;
  border-radius: var(--radius-full);
  background: var(--color-danger);
  color: white;
  font-size: 10px;
  font-weight: var(--weight-bold);
  display: flex;
  align-items: center;
  justify-content: center;
  border: 2px solid var(--color-bg-primary);
}
Sidebar Navigation
CSS
/* ── Sidebar Navigation ── */
.sidebar {
  width: var(--sidebar-width, 260px);
  height: 100vh;
  position: fixed;
  top: 0;
  left: 0;
  z-index: var(--z-sidebar);
  display: flex;
  flex-direction: column;
  overflow: hidden;

  background: var(--color-glass);
  backdrop-filter: blur(var(--blur-prominent));
  -webkit-backdrop-filter: blur(var(--blur-prominent));
  border-right: 1px solid var(--color-border);
}

/* Offset main content */
.main-content {
  margin-left: var(--sidebar-width, 260px);
}

/* Section label */
.sidebar-section-label {
  padding: var(--space-4) var(--space-5) var(--space-1);
  font-size: 10px;
  font-weight: var(--weight-semibold);
  color: var(--color-text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  display: block;
}

/* Nav item */
.sidebar-nav-item {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px var(--space-5);
  font-size: 15px;
  font-weight: var(--weight-regular);
  color: var(--color-text-secondary);
  text-decoration: none;
  border: none;
  background: none;
  width: 100%;
  text-align: left;
  cursor: pointer;
  position: relative;
  transition: color var(--duration-fast) var(--easing-standard),
              background var(--duration-fast) var(--easing-standard);
}

.sidebar-nav-item:hover {
  color: var(--color-text-primary);
  background: var(--color-fill-quaternary);
}

.sidebar-nav-item.active {
  color: var(--color-accent);
  background: var(--color-accent-tint);
  font-weight: var(--weight-medium);
}

/* Active indicator bar */
.sidebar-nav-item.active::before {
  content: '';
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 3px;
  background: var(--color-accent);
  border-radius: 0 2px 2px 0;
}

/* Mobile: collapsed sidebar becomes a sheet */
@media (max-width: 768px) {
  .sidebar {
    transform: translateX(-100%);
    transition: transform var(--duration-normal) var(--easing-standard);
  }
  .sidebar.open {
    transform: translateX(0);
  }
  .main-content {
    margin-left: 0;
  }
}