install
source · Clone the upstream repo
git clone https://github.com/ComeOnOliver/skillshub
Claude Code · Install into ~/.claude/skills/
T=$(mktemp -d) && git clone --depth=1 https://github.com/ComeOnOliver/skillshub "$T" && mkdir -p ~/.claude/skills && cp -r "$T/skills/pproenca/dot-skills/ios-navigation" ~/.claude/skills/comeonoliver-skillshub-ios-navigation-cef4ec && rm -rf "$T"
manifest:
skills/pproenca/dot-skills/ios-navigation/SKILL.mdsource content
iOS Navigation (Modular MVVM-C)
Opinionated navigation enforcement for SwiftUI apps using the clinic modular architecture. Focus on coordinator + route shell wiring, feature isolation, and resilient push/sheet/deep-link flows.
Non-Negotiable Constraints (iOS 26 / Swift 6.2)
macro on every navigation view,@Equatable
neverAnyView
everywhere,@Observable
/ObservableObject
never@Published- App-target coordinators own
; route shells ownNavigationPath
mappings.navigationDestination - Coordinator-owned modal state, inline
booleans for sheets never@State - Domain layer defines coordinator protocols; concrete coordinators stay out of feature modules
Clinic Architecture Contract (iOS 26 / Swift 6.2)
All guidance in this skill assumes the clinic modular MVVM-C architecture:
- Feature modules import
+Domain
only (neverDesignSystem
, never sibling features)Data - App target is the convergence point and owns
, concrete coordinators, and Route Shell wiringDependencyContainer
stays pure Swift and defines models plus repository,Domain
,*Coordinating
, andErrorRouting
contractsAppError
owns SwiftData/network/sync/retry/background I/O and implements Domain protocolsData- Read/write flow defaults to stale-while-revalidate reads and optimistic queued writes
- ViewModels call repository protocols directly (no default use-case/interactor layer)
When to Apply
Reference these guidelines when:
- Designing navigation hierarchies with NavigationStack or NavigationSplitView
- Choosing between push, sheet, and fullScreenCover
- Implementing hero animations, zoom transitions, or gesture-driven dismissals
- Building multi-step flows (onboarding, checkout, registration)
- Using @Observable with @Environment and @Bindable for shared navigation state
- Reviewing code for navigation anti-patterns and modular architecture compliance
- Adding deep linking, state restoration, or tab persistence
- Ensuring VoiceOver and reduce motion support for navigation
Rule Categories by Priority
| Priority | Category | Impact | Prefix |
|---|---|---|---|
| 1 | Navigation Architecture | CRITICAL | |
| 2 | Navigation Anti-Patterns | CRITICAL | |
| 3 | Transition & Animation | HIGH |
anim- |
| 4 | Modal Presentation | HIGH | modal- |
| 5 | Flow Orchestration | HIGH | flow- |
| 6 | Navigation Performance | MEDIUM-HIGH | perf- |
| 7 | Navigation Accessibility | MEDIUM | ally- |
| 8 | State & Restoration | MEDIUM | state- |
Quick Reference
1. Navigation Architecture (CRITICAL)
- Use NavigationStack over deprecated NavigationViewarch-navigation-stack
- Use value-based NavigationLink over destination closuresarch-value-based-links
- Register navigationDestination at stack rootarch-destination-registration
- Use navigationDestination(item:) for optional-based navigation (iOS 26 / Swift 6.2)arch-destination-item
- Define routes as Hashable enumsarch-route-enum
- Use NavigationSplitView for multi-column layoutsarch-split-view
- Extract navigation logic into Observable coordinatorarch-coordinator
- Use @Environment with @Observable and @Bindable for shared statearch-observable-environment
- Handle deep links by appending to NavigationPatharch-deep-linking
- Use NavigationPath for heterogeneous type-erased navigationarch-navigation-path
- Apply @Equatable macro to every navigation viewarch-equatable-views
- Use @Observable only — never ObservableObject or @Publishedarch-observable-only
- Never use AnyView in navigation — use @ViewBuilder or genericsarch-no-anyview
- Present all modals via coordinator — never inline @Statearch-coordinator-modals
2. Navigation Anti-Patterns (CRITICAL)
- Avoid mixing NavigationLink(destination:) with NavigationLink(value:)anti-mixed-link-styles
- Avoid scattering navigationDestination across viewsanti-scattered-destinations
- Avoid sharing NavigationStack across tabsanti-shared-stack
- Avoid hiding back button without preserving swipe gestureanti-hidden-back-button
- Avoid heavy work in view initializersanti-navigation-in-init
- Avoid hamburger menu navigationanti-hamburger-menu
- Avoid programmatic tab selection changesanti-programmatic-tab-switch
3. Transition & Animation (HIGH)
- Use zoom navigation transition for hero animations (iOS 18+)anim-zoom-transition
- Use matchedGeometryEffect only within same view hierarchyanim-matched-geometry-same-view
- Use modern spring animation syntax (iOS 26 / Swift 6.2)anim-spring-config
- Use interactive spring animations for gesture-driven transitionsanim-gesture-driven
- Style transition sources with shape and backgroundanim-transition-source-styling
- Respect reduce motion for all navigation animationsanim-reduce-motion-transitions
- Use onScrollGeometryChange for scroll-driven transitions (iOS 18+)anim-scroll-driven
4. Modal Presentation (HIGH)
- Use push for drill-down, sheet for supplementary contentmodal-sheet-vs-push
- Use presentation detents for contextual sheet sizingmodal-detents
- Use fullScreenCover only for immersive standalone experiencesmodal-fullscreen-cover
- Place .sheet on container view, not on NavigationLinkmodal-sheet-placement
- Guard unsaved changes with interactiveDismissDisabledmodal-interactive-dismiss
- Use separate NavigationStack inside modalsmodal-nested-navigation
5. Flow Orchestration (HIGH)
- Give each tab its own NavigationStackflow-tab-independence
- Use NavigationStack with route array for multi-step flowsflow-multi-step
- Use NavigationSplitView with selection binding for sidebarflow-sidebar-navigation
- Use sidebarAdaptable TabView for iPad tab-to-sidebar (iOS 18+)flow-tab-sidebar-adaptive
- Implement pop-to-root by clearing NavigationPathflow-pop-to-root
- Keep screens independent of parent navigation contextflow-screen-independence
6. Navigation Performance (MEDIUM-HIGH)
- Use value-based NavigationLink for lazy destination constructionperf-lazy-destinations
- Use .task for async data loading on navigationperf-task-modifier
- Own @Observable state with @State, pass as plain propertyperf-state-object-ownership
- Avoid side effects in view bodyperf-avoid-body-side-effects
7. Navigation Accessibility (MEDIUM)
- Mark navigation section headers for VoiceOver rotorally-rotor-headers
- Manage focus after programmatic navigation eventsally-focus-after-navigation
- Group related navigation elements to reduce swipe countally-group-navigation-elements
- Hide decorative navigation elements from VoiceOverally-hide-decorative-navigation
- Use @FocusState for keyboard navigation in formsally-keyboard-focus
8. State & Restoration (MEDIUM)
- Make route enums Codable for navigation persistencestate-codable-routes
- Use SceneStorage for per-scene navigation persistencestate-scene-storage
- Persist selected tab with SceneStoragestate-tab-persistence
- Parse deep link URLs into route enumsstate-deep-link-urls
- Avoid defining NavigationPath at App levelstate-avoid-app-level-path
How to Use
Read individual reference files for detailed explanations and code examples:
- Section definitions - Category structure and impact levels
- Rule template - Template for adding new rules
Reference Files
| File | Description |
|---|---|
| references/_sections.md | Category definitions and ordering |
| assets/templates/_template.md | Template for new rules |
| metadata.json | Version and reference information |