Unexpected Layout Shift with ignoresSafeArea in SwiftUI TabView within NavigationStack

Hello everyone,

I've encountered a strange behaviour in SwiftUI while working with a TabView inside a NavigationStack. The issue arises when using the .ignoresSafeArea(.container, edges: .bottom) modifier. Here's the code to reproduce the issue:

struct ContentView: View {
    
    @State var currentIndex: Int = 0
    
    var body: some View {
        NavigationStack {
            TabView(selection: $currentIndex) {
                VStack {
                    Text("One")
                    Text("Two")
                    Text("Three")
                    Spacer()
                    Text("Four")
                }
                .background(.yellow)
                .tag(0)

                VStack {
                    Text("One")
                        
                    Text("Two")
                    Text("Three")
                    Spacer()
                    Text("Four")
                }
                .background(.red)
                .tag(1)
            }
            .ignoresSafeArea(.container, edges: .bottom)
            .tabViewStyle(.page(indexDisplayMode: .never))
        }
    }
}

Issue Description:

When I apply the.ignoresSafeArea(.container, edges: .bottom) modifier to the TabView view, the layout extends to the bottom, as expected, but with an unexpected slight padding. This padding causes the content within the TabView to shift upwards, resulting in it being partially cut off at the top.

However, if I add a non-transparent background to the TabView (for example, using .background(.red.opacity(0.001))), the layout shift does not occur, and the content is displayed correctly.

Observations:

The issue occurs only when the background is transparent or not explicitly set. When a non-transparent background is applied, even with minimal opacity, the issue disappears.

Screenshots:

With .ignoresSafeArea and transparent background (Content shifted and partially cut off).

With .ignoresSafeArea and non-transparent background (Content displayed correctly).

Questions:

Is this behavior expected, or is it a bug in SwiftUI? Is there a recommended workaround for maintaining a clear background while avoiding the layout shift? Any insights or suggestions would be greatly appreciated!

Thank you!

@lucab You don't necessarily need to ignore the safe areas insets to extend to the bottom. Specifying the tabViewStyle and indexViewStyle should get you close :

    var body: some View {
        NavigationStack {
            TabView(selection: $currentIndex) {
                ....
            }
            .tabViewStyle(.page(indexDisplayMode: .always))
            .indexViewStyle(.page(backgroundDisplayMode: .always))
        }
    }

Adding .ignoresSafeArea(edges: .bottom) to the TabView, will conflict with the home indicator.

Came here to say thank you — this issue is still present, and your solution helped!

Instead of going to the next image, my TabView (nested in a VStack that has .ignoresSafeArea(edges: .vertical)) shifted the image up and then refused to switch from there on — unless you manually swipe.

It only seems to happen when the TabView extends beyond the safe area. Otherwise, everything works fine even without the fix.

Here’s the setup:

VStack(alignment: .leading, spacing: 0) {
    TabView {
        ForEach(viewModel.state.backgroudImages, id: \.self) { imageResource in
            Image(imageResource)
                .resizable()
                .scaledToFill()
        }
    }
    .tabViewStyle(PageTabViewStyle())
    .indexViewStyle(PageIndexViewStyle(backgroundDisplayMode: .always))
    .background(.red.opacity(0.001)) // This line did the trick

    // Other content
}
.ignoresSafeArea(edges: .vertical)
.dynamicTypeSize(...DynamicTypeSize.large)
.toolbar {
    toolbarItems
}
.navigationTitle("Get AppName Pro")
.navigationBarTitleDisplayMode(.inline)

.background(.red.opacity(0.001)) — just that — and the switching works perfectly:

Without it, tapping on the PageIndex causes this broken behavior:

Unexpected Layout Shift with ignoresSafeArea in SwiftUI TabView within NavigationStack
 
 
Q