SwiftUI: Sheet presented from List row is not removed from screen when row is removed

I noticed if I show a sheet from a List row, then remove the row the sheet isn't removed from the screen like it is if using VStack or LazyVStack.

I'd be interested to know the reason why the sheet isn't removed from the screen in the code below. It only occurs with List/Form. VStack/LazyVStack gives the expected result. I was wondering if it is an implementation issue, e.g. since List is backed by UICollectionView maybe the cells can't be the presenter of the sheet for some reason.

  1. Launch on iPhone 16 Pro Simulator iOS 18.2
  2. Tap "Show Button"
  3. Tap "Show Sheet"

What is expected: The sheet should disappear after 5 seconds. And I don't mean it should dismiss, I just mean removed from the screen. Similarly if the View that showed the sheet was re-added and its show @State was still true, then the sheet would be added back to the screen instantly without presentation animation.

What actually happens: Sheet remains on screen despite the row that presented the sheet being removed.

Xcode 16.2 iOS Simulator 18.2.

struct ContentView: View {
    @State var showButton = false
    var body: some View {
        Button("\(showButton ? "Hide" : "Show" ) Button") {
            showButton = true
            Task {
                try? await Task.sleep(for: .seconds(5))
                self.showButton = false
            }
        }
        
        //LazyVStack { // does not have this problem
        List {
            if showButton {
                SheetButton()
            }
        }
    }
}

struct SheetButton: View {
    @State var sheet = false
    @State var counter = 0
    
    var body: some View {
        Text(counter, format: .number)
        
        Button("\(sheet ? "Hide" : "Show") Sheet") {
            counter += 1
            sheet.toggle()
        }
        .sheet(isPresented: $sheet) {
            Text("Wait... This should auto-hide in 5 secs. Does not with List but does with LazyVStack.")
            Button("Hide") {
                sheet = false
            }
            .presentationDetents([.fraction(0.3)])
        }
        // .onDisappear { sheet = false }  // workaround
    }
}

I can work around the problem with .onDisappear { sheet = false } but I would prefer the behaviour to be consistent across the container controls.

Could you test on iOS 18.3 and iOS 18.4 Beta?

I tested on those OS versions and wasn't able to reproduce the issue.

Thanks for your reply, sorry for the delay for some reason the alert wasn't enabled for replies despite being the author, I have enabled it now and will try to remember to do that for all my future posts.

That's strange you can't reproduce. I can confirm the issue also exists on iOS 18.3.1 device and iOS 18.4 Beta simulator.

18.3.1 test:

  • Xcode Version 16.2 (16C5032a)
  • iOS min deployment 18.2
  • Swift 5 Language Version
  • Deployed to device: iPhone 14 Pro, iOS 18.3.1

18.4 beta test:

  • Xcode Version 16.3 beta (16E5104o)
  • iOS min deployment 18.4
  • Swift 5 Language Version
  • Deployed to simulator: iPhone 16 Pro, iOS 18.4 (22E5200m)

Just to confirm how to test: the list rows and the sheet are expected to automatically disappear. But only the rows do, i.e. ends up like this:

SwiftUI: Sheet presented from List row is not removed from screen when row is removed
 
 
Q