Version: 2.0.0 Last Updated: 2026-04-19 Purpose: Detailed guide for implementing mobile navigation patterns in Encore Health OSDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
Navigation documentation index: NAVIGATION_GUIDE_INDEX.md
Major changes vs v1.4.0:
- Removes references to
MobileMenuSheet(consolidated intoMobileNavMoreperResponsiveNav.tsx2026-Q1).- Updates the component map to reflect the current
MobileNav(4-slot dock + More drawer),MobileNavMore,MobileNavDockSheetContent,MobileSidebarNav(feature-flagged).- Adds the new
BottomTabBarshared primitive for core-level bottom navs (CE today; HR/RH later).- Aligns CSS-var examples with production (
--mobile-nav-height: 76px,--mobile-header-height: 48px,--mobile-header-context-height: 32px).- Codifies the mobile-component-location convention (cores//components/mobile/).
- Edge-swipe back is now bound to the main scroll area (PR-3.2 in the mobile-gestures consistency plan), not just the header.
Overview
Encore Health OS uses a mobile-first navigation system:- Bottom tab bar for primary navigation (
< 768 px). - Top header with logo, search, notifications, and a contextual primary action.
- Mobile breadcrumbs (last 2 segments) for hierarchical context.
- More drawer (
MobileNavMore+MobileNavDockSheetContent) for secondary navigation, themes, sign-out, and module switching. - Desktop: Sidebar (
SidebarProvider+AppSidebar+SidebarInset) at≥ 768 px. Other nav modes (Dock, Taskbar) live inNavModeContext.
Quick Reference
Component map (current)
| Component | Path | Purpose |
|---|---|---|
ResponsiveNav | src/platform/navigation/ResponsiveNav.tsx | Top-level mobile/desktop switch |
MobileNav | src/platform/navigation/MobileNav.tsx | 4-slot bottom dock with More button |
MobileNavMore | src/platform/navigation/MobileNavMore.tsx | Sheet trigger for the More drawer |
MobileNavDockSheetContent | src/platform/navigation/MobileNavDockSheetContent.tsx | Drawer body (modules, settings, theme, sign-out) |
MobileHeader | src/platform/navigation/MobileHeader.tsx | Top app bar (logo, back, search, notifications) |
MobileBreadcrumbs | src/platform/navigation/MobileBreadcrumbs.tsx | Compact 2-segment crumb row |
MobileOrgSwitcher | src/platform/navigation/MobileOrgSwitcher.tsx | Multi-org switcher in context row |
MobileSidebarNav | src/platform/navigation/MobileSidebarNav.tsx | Feature-flagged (pf.mobile_sidebar_nav) full-tree drawer |
MobileModuleSwitcher | src/platform/modules/MobileModuleSwitcher.tsx | Module grid inside the More drawer |
MobileModuleIcon | src/platform/modules/MobileModuleIcon.tsx | Module icon helper |
BottomTabBar | src/platform/navigation/components/BottomTabBar.tsx | Reusable mobile bottom-tab primitive (module-level navs) |
useModuleBottomTabs | src/platform/navigation/hooks/useModuleBottomTabs.ts | Derives bottom-bar tabs from MODULE_REGISTRY navGroups |
MobileModuleNavStrip (new) | src/platform/navigation/components/MobileModuleNavStripImpl.tsx | Scrollable chip bar for in-module section switching |
useRoleBasedDefaults (new) | src/platform/navigation/hooks/useRoleBasedDefaults.ts | Role-based default shortcut presets |
useNavigationFrequency (new) | src/platform/navigation/hooks/useNavigationFrequency.ts | Tracks module visit frequency for suggestions |
MobileMenuSheetwas removed in 2026-Q1 — its responsibilities are now inMobileNavMore+MobileNavDockSheetContent.
Context-aware bottom navigation (2026-Q2)
MobileNav now operates in two modes:
- Platform mode (default): Shows the user’s 3 customizable shortcut slots + More. Active when no module is detected.
- Module mode: When the user is inside a module (detected via
useModuleRouting), the bottom bar automatically transforms to show that module’s top navigation sections (derived fromMODULE_REGISTRY.navGroupsviauseModuleBottomTabs), plus the More button.
initialModuleId prop).
Dead core-level MobileBottomNav files in CL, PM, and HR were removed in 2026-Q2. CE’s MobileBottomNav / MobileCrmShell remain for CE-specific features (QuickLogFAB, offline indicator) but the CE tab bar will be superseded by the platform context-aware pattern.
Common patterns
Key requirements
- Touch targets: ≥ 44 × 44 px (WCAG 2.1 AAA, Apple HIG). Use
min-w-[44px] min-h-[44px]. - Safe areas: all fixed surfaces apply
env(safe-area-inset-*)via the CSS vars below. - Breakpoints: mobile
< 768 px, desktop≥ 768 px. UseuseIsMobile()from@/shared/lib/hooks/use-mobile(do not useuseMediaQueryfor the mobile breakpoint). - Z-index: bottom nav uses
z-50; app-lock overlay (PF-79) wins atz-[100]. - Content padding: the
<main>insideResponsiveNavalready pads top + bottom for header/nav heights using CSS vars.
Common issues
| Symptom | Fix |
|---|---|
| Content hidden behind bottom nav | The mobile <main> already adds pb-[calc(var(--mobile-nav-height,64px) + var(--safe-area-inset-bottom,0px))]. If you bypass it, add the same padding. |
| Safe area not honored | Make sure the viewport meta tag has viewport-fit=cover (✅ in index.html). |
| Touch target too small | Add min-w-[44px] min-h-[44px] to the button. |
| Hydration flash on mobile | useIsMobile now reads window.innerWidth synchronously on mount (PR-3.1) — verify your code calls the hook from @/shared/lib/hooks/use-mobile. |
CSS Variables (Single Source of Truth)
Defined insrc/index.css:
index.css):
.safe-area-top/.safe-area-bottom/.safe-area-left/.safe-area-right.no-pull-refresh(overscroll-behavior-y: contain).scrollbar-thin/.scrollbar-x/.scrollbar-yfor scroll-area styling
1. Architecture
useEdgeSwipe for back navigation is bound to the mobile main scroll container (PR-3.2), so it can fire from anywhere in the left 20 px of the viewport — not just the 48 px header.
2. Bottom Navigation
Platform MobileNav
The platform-level bottom nav lives at src/platform/navigation/MobileNav.tsx and renders 4 slots + a More button:
useMobileNavPreferences (per-user) filtered against permission via useMobileNavAllowedShortcuts. The list is configured in mobile-nav-config.ts. Long-pressing the More button opens the Customize dialog.
Active-state visuals:
- A sliding pill underline animates between the active item.
aria-current="page"is set on the active link.
Core-level BottomTabBar (new)
For modules that need a module-scoped bottom nav (today only CE; potentially HR / RH for field staff), use the shared primitive at src/platform/navigation/components/BottomTabBar.tsx:
Stacking with the platform nav
A core-levelBottomTabBar does not replace the platform MobileNav — both can render. To avoid double-stacking:
- Either offset the core nav above the platform nav (default), or
- Hide the platform nav for the route by checking
useNavigation().isSubModuleRouteand conditionally rendering. (Decision: keep both for now; CE has confirmed the dual-nav UX.)
3. More Drawer (MobileNavMore + MobileNavDockSheetContent)
Replaces the legacy MobileMenuSheet. Contents:
- User profile header with avatar.
- Notifications inbox link.
- AI Assistant launch.
- Theme toggle.
- Phone / Log Call (RingCentral integration).
- All modules grid (collapsible by category).
- Search.
- Sign out.
MobileNav.
4. Safe Area Insets
Already wired intoindex.css. Consumers reference the CSS vars:
Test devices
- iPhone X / XS / 11 / 12 / 13 / 14 / 15 (notched + home indicator)
- iPhone 14 / 15 Pro (Dynamic Island)
- Pixel 6 / 7 / 8 (home indicator)
- iPad Pro / iPad Air
5. Touch Targets
gap-2 (8 px) minimum between adjacent targets.
6. Mobile-Component Location Convention (new)
Cores have grown three different conventions for “where do mobile-only components live?”:- CE: dedicated
src/cores/ce/components/mobile/folder. - CL / HR:
Mobile<Name>.tsxcolocated with desktop peer. - FM / LO / RH: nothing (all responsive in one file).
- Mobile-only components that don’t have a 1:1 desktop sibling → put under
src/cores/{core}/components/mobile/. - Mobile variants of existing components (small) → colocate as
<Name>.mobile.tsxpeer to<Name>.tsx.
Mobile<Domain><Surface>(e.g.MobileVitalsKeypad,MobileBottomNav).- Use Sheet not Drawer / Modal in new file names (per root
AGENTS.md). Existing names withDrawerare grandfathered until renamed (seeMobileVitalsDrawer → MobileVitalsSheetrename in PR-2.5).
src/cores/AGENTS.md and per-core AGENTS files where mobile work is active.
7. Edge Swipe Back Navigation (updated)
The hook (useEdgeSwipe) is now bound to the main mobile scroll container in ResponsiveNav rather than only MobileHeader. This means a left-edge swipe anywhere in the visible viewport — not just the 48 px header — triggers back navigation.
style={{ touchAction: 'pan-x' }} to opt out.
8. Offline Navigation
Use the existinguseOnlineStatus hook. The MobileHeader shows an offline banner; MobileNav already hides routes that require online when offline.
vite.config.ts Workbox config; navigation falls back to the cached shell when offline.
9. Navigation Error Boundaries
Use the platformRouteErrorBoundary (src/platform/navigation/components/RouteErrorBoundary.tsx) — wraps each route module. Reports to Sentry; exposes a “Retry” + “Go home” UI.
10. Testing Checklist
Functional
- Bottom nav appears on mobile (
< 768 px), hidden on desktop. - More drawer opens/closes.
- Edge swipe back navigates one level (route depth ≥ 2).
- Customize dialog (long-press More) saves preferences.
- Core-level
BottomTabBarfilters by permission.
Safe areas
- iPhone X+ / Pro models — no overlap with notch / Dynamic Island.
- Pixel 7+ — bottom nav above home indicator.
- Landscape orientation — left/right insets honored.
Touch targets
- All bottom-nav buttons ≥ 44 × 44 px.
- Header icon buttons ≥ 44 × 44 px.
- Drawer rows ≥ 44 px tall.
Accessibility
-
aria-current="page"on active tab. -
aria-labelon every icon-only button. -
Esccloses the More drawer. - Skip-to-content link works from keyboard.
- Keyboard arrow keys navigate between bottom-nav slots (
MobileNavalready implements this).
Hydration / first paint
- No desktop chrome flash on real mobile devices (PR-3.1 fix in
useIsMobile). - Boot splash transitions cleanly.
Cross-browser
- iOS Safari 14+ ✅
- Android Chrome 90+ ✅
- Firefox / Edge mobile
11. Mobile Breadcrumbs
MobileBreadcrumbs shows the last 2 segments of the route. Detail/edit pages set the dynamic trailing crumb via useEntityBreadcrumb(data, (e) => e.name) from @/shared/lib/hooks/useEntityBreadcrumb. Static labels come from BASE_ROUTE_LABELS in src/platform/navigation/route-labels.ts (audit: npm run audit:routes-navigation).
@/shared/ui/breadcrumb primitives directly — header auto-render is the standard.
12. Best Practices Summary
- Use CSS vars (
--mobile-nav-height,--safe-area-inset-*) for all fixed-element spacing; never hard-code. - Keep touch targets at 44 × 44 px minimum.
- Use
useIsMobilefor the 768-px breakpoint;useMediaQueryis reserved for non-standard breakpoints and is@deprecatedfor the mobile case. - Place mobile-only components under
src/cores/{core}/components/mobile/. - Use the
Sheetprimitive for slide-up panels (not “Drawer” or “Modal” in new code). - Use
BottomTabBarfor core-level mobile navs (CE today; HR/RH if needed). - Use
SwipeableCardShell(from@/platform/gestures) instead of hand-rolled*Swipeable.tsxwrappers. - Set
aria-current="page"on active tabs andaria-labelon icon-only buttons. - Honor
prefers-reduced-motionautomatically — Phase 1 gesture hooks already do this (PR-3.3). - Test on real notched iOS + home-indicator Android devices (or Chrome DevTools device emulation).
13. Quick Actions Pattern (PF-20)
Quick actions are not in mobile navigation. They appear on overview pages viaQuickActionsSection from @/platform/dashboard/components/QuickActionsSection. The mobile More drawer surfaces a “Quick Actions” entry that opens the command palette.
14. Mobile Swipe Gestures
See Mobile Gesture Guide v2.0.0 (companion document) for the complete catalog of swipe / pinch / multi-touch hooks and components, includingSwipeableCardShell, MobilePullToRefresh, useEdgeSwipe, and Phase 2 user preferences.
15. References
- Constitution §6 — PWA & UI requirements
- Spec: PF-13 PWA & Mobile Navigation Improvements
- Spec: PF-37 Mobile Swipe Gestures
- Spec: PF-79 Mobile App Security (biometric / PIN / session lock)
- Plan: PF Mobile Touch & Scroll Improvement Plan
- Guide: Mobile Gesture Guide v2.0.0
- Guide: Breadcrumb Implementation Guide
- Component:
ResponsiveNav.tsx - Component:
MobileNav.tsx - Component:
BottomTabBar.tsx(new) - Hook:
useIsMobile - WCAG 2.1 Target Size
- Apple HIG Layout — Touch targets
Document status: Active Maintained by: Platform Team Last reviewed: 2026-04-19