Thanks for being a part of WWDC25!

How did we do? We’d love to know your thoughts on this year’s conference. Take the survey here

SwiftUI NavigationSplitView like Apple Music

In the Apple Music app on iPad (horizontal size class == .regular), when a selection is made from the Split View sidebar, the detail switches to a separate UINavigationController for that selection, where we can push/pop views. If we make a different selection from the sidebar, we get another UINavigationController to manipulate. If we return to the first selection, the detail view is still showing the stack contents for that controller.

I am trying to get the same behavior from NavigationSplitView in SwiftUI, but the detail view will reset its presented controller to its root. I think this is because NavigationSplitView uses whatever NavigationStack it finds in the detail hierarchy to manage its contents, effectively erasing the per-view stack contents. I have tried various methods of saving and restoring the navigation path without any luck. Any ideas on how to approach this?

I have included a very simple example to show what I'm talking about.

import SwiftUI

struct ExampleView: View {
  enum Selection: String, CaseIterable {
    case letters
    case numbers
  }
  
  @State private var selection: Selection?
  
  var body: some View {
    NavigationSplitView {
      List(selection: $selection) {
        ForEach(Selection.allCases, id: \.self) { selection in
          NavigationLink(value: selection) {
            Text(selection.rawValue.capitalized)
          }
        }
      }
      .navigationTitle("Sidebar")
      
    } detail: {
      switch selection {
      case .letters:
        self.lettersView
        
      case .numbers:
        self.numbersView
        
      default:
        Text("Make a selection")
      }
    }
  }
  
  var lettersView = LettersView()
  var numbersView = NumbersView()
}

struct ExampleView_Previews: PreviewProvider {
  static var previews: some View {
    ExampleView()
  }
}

// MARK: -
struct LettersView: View {
  private let letters = ["a", "b", "c", "d", "e", "f"]
  @State private var path = NavigationPath()
  
  var body: some View {
    NavigationStack(path: $path) {
      List {
        ForEach(letters, id: \.self) { letter in
          NavigationLink(value: letter) {
            Text(letter.uppercased())
          }
        }
      }
      .navigationTitle("Letters")
      .navigationDestination(for: String.self) { letter in
        Text(letter.uppercased()).font(.largeTitle)
      }
    }
  }
}

// MARK: -
struct NumbersView: View {
  private let numbers = Array(0..<6)
  @State private var path = NavigationPath()
  
  var body: some View {
    NavigationStack(path: $path) {
      List {
        ForEach(numbers, id: \.self) { number in
          NavigationLink(value: number) {
            Text(String(number))
          }
        }
      }
      .navigationTitle("Numbers")
      .navigationDestination(for: Int.self) { number in
        Text(String(number)).font(.largeTitle)
      }
    }
  }
}

@jep struggeling with the same issue. Have you found a solution?

SwiftUI NavigationSplitView like Apple Music
 
 
Q