Unexpected behavior of NavigationStack with List inside sheets

I've reported this via Feedback Assistant (FB13190469), but maybe someone knows some workaround. So, very simple code, very easy to replicate. Works (or better say doesn't work) on either Simulators or iPhones. Very simple code:

struct ContentView: View {
    @State private var showSheet: Bool = false
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        NavigationStack {
            Button("Show me", action: { showSheet = true })
        }
        .padding()
        .sheet(isPresented: $showSheet) {
            NavigationStack {
                List {
                    Button("Go away", action: { showSheet = false })
                }
                .navigationBarTitleDisplayMode(.large)
                .navigationTitle("Test")
            }
        }
    }
}

Now, I can't attach video, you can try for yourself: On iOS 17, sheet initializes with .inline title style. If you swipe down a little, it turns into a .large title, but only after. Another problem, is that you can't immediately dismiss sheet with downswipe, you have to make two swipes. Also, if you switch to .inline header, you'll find a big gap between list header and the beginning of the list.

Again, this bug works only inside sheets. Root level views, fullScreenCovers, navigationDestinations, etc. render .navigationBarTitleDisplayMode(.large) normally.

On iOS 16.4 everything works as expected.

Thanks in advance!

Hi!

This is because sheet isn't full screen, so it makes the List scrollable. The other views you mentioned are all full screen views so the list doesn't need to scroll. For now, you can either remove the list, or use .scrollDisabled, but .scrollDisabled will make the title always be inline. Thanks for filing that feedback report though, clearly it is different behavior than earlier.

This is a bit of a hack, but works for me. The issue is caused by a scroll view being drawn at the same time as the rest of the view, if you delay the drawing of the list until after the view has appeared, then the layout will be correct.

struct ContentView: View {
    @State private var showSheet: Bool = false
    @State private var showList: Bool = false
    @Environment(\.dismiss) private var dismiss
    
    var body: some View {
        NavigationStack {
            Button("Show me", action: { showSheet = true })
        }
        .padding()
        .sheet(isPresented: $showSheet) {
            NavigationStack {
                VStack {
                    if showList {
                        List {
                            Button("Go away", action: { showSheet = false })
                        }
                    }
                }
                .navigationBarTitleDisplayMode(.large)
                .navigationTitle("Test")
                .onAppear {
                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
                        showList = true
                    }
                }
            }
        }
    }
}

I am having this same issue, but with Form, and I don't really enjoy using hacky work arounds. I imagine best practice is simply to use inline titles with modals. Hopefully this issue is resolved.

Unexpected behavior of NavigationStack with List inside sheets
 
 
Q