ns-top-nav
Top navigation strategy: native ActionBar vs synthetic header
A screen's top bar is either the native ActionBar (UINavigationBar on iOS, Toolbar on Android) or a synthetic header — ordinary Labels/Buttons in the first row of the page layout. Default to native for any page you navigate to; reserve synthetic for branded tab-root headers that aren't navigation chrome at all.
1. Decision framework
| Screen shape | Use | Why |
|---|---|---|
| Pushed page — has a back affordance (detail views, viewers, sub-flows) | Native <ActionBar> |
Back button, edge-swipe pop, title truncation, safe-area math, dark mode, and current-OS styling (translucency, Liquid Glass on iOS 26) all come from the system for free. A synthetic "‹ Back" row gets none of these and always reads as slightly off. |
| Tab root with branded header — big title + subtitle + custom controls that scroll like content | Synthetic header, actionBarHidden = true |
This is a content header (iOS large-title spirit), not nav chrome. ActionBar can't express subtitle + arbitrary controls without fighting titleView sizing quirks on both platforms. |
| Chrome-free page — TabView shell, full-bleed media, onboarding | No bar: actionBarHidden = true |
Nothing to show; just make the hide explicit (pitfall 1). |
| Native bar, custom middle — native back + actions but bespoke title (logo, segmented control) | <ActionBar> with titleView |
Keeps every native behavior; only the middle is custom. Prefer this over going fully synthetic. |
Native wins whenever navigation is involved: iOS gives the chevron, previous-page label, interactive edge-swipe pop, and long-press history; the OS restyles the bar for dark mode/dynamic type/future redesigns; VoiceOver/TalkBack announce native bars correctly; status-bar/notch insets and truncation are handled. When synthetic is genuinely better, accept the cost — you own safe areas, dark mode, and a11y yourself — and don't imitate a system nav bar (fake "‹ Back" rows sit in the uncanny valley).
2. Architecture: each page decides
In Angular apps, give every page-router-outlet actionBarVisibility="auto" — never never app-wide (it forbids native bars for every page in that Frame). Pages that want the bar declare <ActionBar> as a top-level template sibling of the root layout (it attaches to the Page, not the layout); pages without one must hide it explicitly: