Creating a Master-Detail Interface in SwiftUI
Master-detail interfaces are common in iOS and Mac apps. Select an item from the master view to see additional information in the detail view. In SwiftUI you use two views to create a master-detail interface: NavigationView
and NavigationLink
.
UPDATE
Apple deprecated NavigationView
in iOS 16 and macOS 13. The replacements for NavigationView
are NavigationStack
and NavigationSplitView
, but they require iOS 16+ and macOS 13+. If you want to support earlier OS versions, you must use NavigationView
.
Navigation View
A navigation view is the most common way to create a master-detail interface in SwiftUI. On iOS selecting an item from the master view, which is usually a SwiftUI list, takes you to the detail view. On macOS selecting an item from the master view shows the details in the detail view.
The following code shows how to create a navigation view:
var body: some View {
NavigationView {
MasterView()
DetailView()
}
}
In a real app you will pass data as arguments to the master view and detail view. The data depends on your app, which is why I didn’t supply any arguments in the code listing.
The article Passing Data to SwiftUI Views provides more detailed information on passing data to views.
Navigation Link
The final part of creating a master-detail interface is to add a navigation link in the master view and set its destination to the detail view.
List(items) { item in
NavigationLink(destination: DetailView()) {
Text(item.title)
}
}
This example creates a navigation link for each item in the list. Selecting an item from the list fills the detail view with information about the selected item. In a real app you will pass the data to show in the detail view as an argument to the detail view.
Handling Selection
There are some situations where you may need to hold on to the selection. Mac apps need access to the selected item when deleting an item from a list.
In the master view create a property to store the selection. Make it optional and set its value to nil.
@State private var selectedItem: Item? = nil
When someone selects an item from the list, the selectedItem
property will store it. In the call to create the navigation link, add the tag
and selection
arguments. The tag is usually the current item. The selection is the selected item.
List(items) { item in
NavigationLink(destination: DetailView(),
tag: item,
selection: $selectedItem) {
Text(page.title)
}
}
Sample Project
I put a sample project on master-detail interfaces on GitHub. It builds upon the project from the Make a Markdown Editor in SwiftUI article by displaying a list of Markdown pages to edit. Look at the files ContentView.swift
and PageListView.swift
for the code on making the master-detail interface.