.navigationTitle disappears when using .toolbar and List inside NavigationStack (iOS 26 beta)
Summary
In iOS 26 beta, using .navigationTitle()
inside a NavigationStack
fails to render the title when combined with a .toolbar
and a List
. The title initially appears as expected after launch, but disappears after a second state transition triggered by a button press. This regression does not occur in iOS 18.
Steps to Reproduce
- Use the SwiftUI code sample below (see
viewmodel
andReload
button for state transitions). - Run the app on an iOS 26 simulator (e.g., iPhone 16).
- On launch, the view starts in
.loading
state (shows aProgressView
). - After 1 second, it transitions to
.loaded
and displays the title correctly. - Tap the Reload button — this sets the state back to
.loading
, then switches it to.loaded
again after 1 second. - ❌ After this second transition to
.loaded
, the navigation title disappears and does not return.
Actual Behavior
- The navigation title displays correctly after the initial launch transition from
.loading → .loaded
. - However, after tapping the “Reload” button and transitioning
.loading → .loaded
a second time, the title no longer appears. - This suggests a SwiftUI rendering/layout invalidation issue during state-driven view diffing involving
.toolbar
andList
.
Expected Behavior
The navigation title “Loaded Data” should appear and remain visible every time the view is in .loaded
state.
✅ GitHub Gist including Screen Recording
Sample Code
import SwiftUI
struct ContentView: View {
private let vm = viewmodel()
var body: some View {
NavigationStack {
VStack {
switch vm.state {
case .loading:
ProgressView("Loading...")
case .loaded:
List {
ItemList()
}
Button("Reload") {
vm.state = .loading
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
vm.state = .loaded
}
}
.navigationTitle("Loaded Data")
}
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Menu {
Text("hello")
} label: {
Image(systemName: "gearshape.fill")
}
}
}
}
}
}
struct ItemList: View {
var body: some View {
Text("Item 1")
Text("Item 2")
Text("Item 3")
}
}
@MainActor
@Observable
class viewmodel {
enum State {
case loading
case loaded
}
var state: State = .loading
init() {
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.state = .loaded
}
}
}