NavigationView is a SwiftUI container component for organizing stack-based navigation between screens. NavigationView creates a navigation stack with an automatic navigation bar, title, and back button. Since iOS 16, Apple recommends using NavigationStack. Read more in Apple documentation.
Key Takeaways
NavigationView is a SwiftUI container that wraps a hierarchy of screens and provides a navigation interface. Inside NavigationView, NavigationLink works — an element that replaces the current screen with a new one when pressed. NavigationView automatically adds a navigation bar with a title and a back button.
NavigationView was introduced in iOS 13 alongside SwiftUI. Conceptually, it replaces UINavigationController from UIKit but is implemented declaratively. Instead of manual push/pop, the developer describes the relationship between screens using NavigationLink. The system automatically manages the stack.
NavigationView supports modifiers .navigationTitle, .navigationBarTitleDisplayMode, .toolbar and .searchable. For iOS 16+, Apple introduced NavigationStack, which preserves the NavigationView API but adds programmatic stack management via NavigationPath. For projects supporting iOS 15 and below, NavigationView remains the only option.
NavigationLink is a SwiftUI element that creates a transition to a target screen inside NavigationView or NavigationStack. When NavigationLink is pressed, the system adds the target screen to the navigation stack. The transition animation is the standard push from the right on iOS, adapting to the platform.
struct ContentView: View {
var body: some View {
NavigationView {
List(items) { item in
NavigationLink(destination: DetailView(item: item)) {
Text(item.title)
}
}
.navigationTitle("List")
}
}
}
struct DetailView: View {
let item: Item
var body: some View {
VStack {
Text(item.description)
.navigationTitle(item.title)
.navigationBarTitleDisplayMode(.inline)
}
}
}NavigationLink takes two parameters: destination — the target View, and label — the element the user presses. For lists, the syntax with value and NavigationLink(value:) is convenient — it automatically unselects the cell and works with NavigationPath.
With iOS 16, Apple introduced NavigationStack as a replacement for NavigationView. NavigationStack preserves the declarative syntax but adds a critically important feature — programmatic stack management through the path property of type NavigationPath or an array of Hashable.
| Feature | NavigationView (iOS 13-15) | NavigationStack (iOS 16+) |
|---|---|---|
| Programmatic push | No, only via NavigationLink | Yes, via path.append(value) |
| popToRoot | Only dismiss to root | path.removeLast(path.count) |
| Deep Links | Complex implementation | Built-in support via path |
| Stack typing | No (any View in destination) | Yes (array of Hashable values) |
| iPad SplitView | ColumnStyle / StackStyle | NavigationSplitView (iOS 16+) |
For projects with a minimum version of iOS 16+, use NavigationStack. For iOS 14-15 support — NavigationView. NavigationStack has no direct analogs for older versions, so upgrading requires compatibility checking.
The .toolbar and .navigationTitle modifiers control the content of the navigation bar. .navigationTitle sets the screen title, .navigationBarTitleDisplayMode selects the style: .large (prominent, default) or .inline (compact, like in Settings). .toolbar adds buttons, search, and segmented control.
struct SettingsView: View {
var body: some View {
NavigationStack {
Form {
Section("Profile") {
Text("Username")
Toggle("Notifications", isOn: $notifications)
}
}
.navigationTitle("Settings")
.navigationBarTitleDisplayMode(.large)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button("Save") { save() }
}
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
}
}
}
}
}.searchable is another modifier that integrates a search bar into the navigation bar. Works with both NavigationView and NavigationStack. The search bar automatically hides when scrolling and appears when swiping down. Supports list filtering via a Binding String.
NavigationPath is an iOS 16+ type that represents a navigation stack as a collection of Hashable values. The developer adds elements to path for programmatic transitions, removes them for returning. NavigationPath supports deep links, push notifications, and state restoration.
struct AppNavigation: View {
@State private var path = NavigationPath()
var body: some View {
NavigationStack(path: $path) {
List(categories) { category in
NavigationLink("Category \(category.name)",
value: category)
}
.navigationTitle("Categories")
.navigationDestination(for: Category.self) { category in
ProductListView(category: category)
}
.navigationDestination(for: Product.self) { product in
ProductDetailView(product: product)
}
}
// Programmatic deep link navigation
.onOpenURL { url in
guard let productId = DeepLinkParser.parse(url) else { return }
path.append(Product(id: productId))
}
}
}.navigationDestination(for:) registers a data type for which to show a screen. When a value of this type is added to the path, the system automatically creates the target View. This approach replaces explicit NavigationLink(destination:) and makes navigation strictly typed.
NavigationView and NavigationStack work on all Apple platforms: iOS, iPadOS, watchOS, tvOS and macOS. Behavior adapts to the screen. On iPad, NavigationStack supports NavigationSplitView, which replaces UISplitViewController from UIKit and displays two columns on a wide screen.
NavigationSplitView (iOS 16+) splits the screen into sidebar (list) and detail. On iPhone, the sidebar is hidden, showing only detail via NavigationLink. On iPad, sidebar and detail are displayed simultaneously in split mode.
struct AdaptiveNavigation: View {
@State private var selectedCategory: Category?
var body: some View {
NavigationSplitView {
List(categories, selection: $selectedCategory) { category in
Text(category.name)
}
.navigationTitle("Categories")
} detail: {
ProductListView(category: selectedCategory)
}
}
}NavigationSplitView automatically selects the optimal display mode for each device. On iPhone in portrait — stack, on iPad and iPhone in landscape — split. The developer doesn't need to write separate code for different size classes.
Frequently Asked Questions
NavigationView is the old API (iOS 13-15), supports only declarative NavigationLink. NavigationStack is the new API (iOS 16+), adds path for programmatic navigation, deep links and a strictly typed stack. NavigationStack is recommended by Apple for new projects.
Through the .toolbar modifier with ToolbarItem. For example: .toolbar { ToolbarItem(placement: .navigationBarTrailing) { Button('Settings') { } } }. Placement determines the position: trailing (right), leading (left), principal (center).
The title is set via .navigationTitle('Title'). Style — .navigationBarTitleDisplayMode(.large) or .inline. Large — prominent title in iOS Music style, inline — compact, like in Settings. The style can be changed for each screen individually.
Three ways: via value (NavigationLink(value:item) { Label }, iOS 16+), via destination + label, via isActive for programmatic transition. NavigationLink with value is cleaner for lists as it doesn't require creating the target View before the transition.
Yes. NavigationView and NavigationStack are available on iOS, iPadOS, watchOS, tvOS and macOS. On watchOS navigation uses the interface hierarchy with the Digital Crown, on tvOS — focus-based input with the remote. Behavior adapts to the platform automatically.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also