I am attempting to indicate a fullScreenCover when the consumer faucets the third tab as an alternative of really switching to that tab. The difficulty is that resetting selectedTab = oldValue in onChange breaks the NavigationStack push/pop animations within the earlier tab.
After I reset the tab choice synchronously, the NavigationStack within the earlier tab loses its animations – no push/pop transitions work anymore till I swap tabs away and again.
Damaged code:
struct ContentView: View {
@State non-public var selectedTab: Int = 0
@State non-public var showSheet: Bool = false
var physique: some View {
TabView(choice: $selectedTab) {
Tab("First", systemImage: "1.circle.fill", worth: 0) {
FirstTabView()
}
Tab("Second", systemImage: "2.circle.fill", worth: 1) {
SecondTabView()
}
Tab("Sheet", systemImage: "ellipsis", worth: 2, function:.search) {
EmptyView()
}
}
.onChange(of: selectedTab) { oldValue, newValue in
if newValue == 2 {
showSheet = true
selectedTab = oldValue // This breaks NavigationStack animations!
}
}
.fullScreenCover(isPresented: $showSheet) {
SheetView()
}
}
}
Damaged navigation animation right here: https://youtube.com/shorts/SeBlTQxbV68
Including a small delay earlier than resetting the tab choice appears to repair it:
.onChange(of: selectedTab) { oldValue, newValue in
if newValue == 2 {
Activity { @MainActor in
showSheet = true
attempt? await Activity.sleep(for: .seconds(0.25))
selectedTab = oldValue
}
}
}
Working with delay: https://youtube.com/shorts/B4AbX72vc3g
import SwiftUI
struct FirstTabView: View {
var physique: some View {
NavigationStack {
VStack {
Textual content("Fundamental View")
}
}
}
}
struct SecondTabView: View {
@State non-public var gadgets: [String] = ["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]
var physique: some View {
NavigationStack {
Listing(gadgets, id: .self) { merchandise in
NavigationLink(worth: merchandise) {
Textual content(merchandise)
}
}
.navigationTitle("Second Tab")
.navigationBarTitleDisplayMode(.inline)
.navigationDestination(for: String.self) { merchandise in
Textual content(merchandise)
}
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(motion: {
gadgets.append("Merchandise (gadgets.depend + 1)")
}) {
Picture(systemName: "plus")
}
}
}
}
}
}
struct SheetView: View {
@Atmosphere(.dismiss) non-public var dismiss
var physique: some View {
NavigationStack {
VStack {
Textual content("Good day World")
}
.navigationTitle("Sheet View")
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button(motion: {
dismiss()
}) {
Picture(systemName: "xmark")
}
}
}
}
}
}
struct ContentView: View {
@State non-public var selectedTab: Int = 0
@State non-public var showSheet: Bool = false
var physique: some View {
TabView(choice: $selectedTab) {
Tab("First", systemImage: "1.circle.fill", worth: 0) {
FirstTabView()
}
Tab("Second", systemImage: "2.circle.fill", worth: 1) {
SecondTabView()
}
Tab("Sheet", systemImage: "ellipsis", worth: 2, function:.search) {
EmptyView()
}
}
.onChange(of: selectedTab) { oldValue, newValue in
if newValue == 2 {
Activity { @MainActor in
showSheet = true
attempt? await Activity.sleep(for: .seconds(0.25))
selectedTab = oldValue
}
}
}
.fullScreenCover(isPresented: $showSheet) {
SheetView()
}
}
}
#Preview {
ContentView()
}
- Why does the synchronous reset break NavigationStack animations?
- Is there a cleaner answer that does not require a hardcoded delay?
- Is that this a recognized iOS 26 bug with TabView and NavigationStack?
Atmosphere: iOS 26.1, Xcode 26.1

