SwiftUI.cc
Fix
Fix

SwiftUI Sheet Not Dismissing: Causes & Fix

A SwiftUI sheet doesn't dismiss when dismiss() is called, often due to incorrect environment usage or state management.

5 min readUpdated 2026-06

The Problem

When using a sheet in SwiftUI, it may fail to dismiss even when calling dismiss(). Here's an example of the broken implementation:

struct ContentView: View {
    @State private var isSheetPresented = false

    var body: some View {
        Button("Show Sheet") {
            isSheetPresented = true
        }
        .sheet(isPresented: $isSheetPresented) {
            SheetView()
        }
    }
}

struct SheetView: View {
    @Environment(\.presentationMode) var presentationMode

    var body: some View {
        Button("Dismiss") {
            presentationMode.wrappedValue.dismiss()
        }
    }
}

Root Cause

The issue often stems from incorrect use of the presentationMode environment variable or SwiftUI's sheet binding mechanics. In particular, SwiftUI does not always propagate the correct presentation context when the sheet is presented via a binding. This can lead to the presentationMode.dismiss() call having no effect because it doesn't reference the actual presented view controller.

Additionally, if the isPresented binding is not updated correctly or if it's being observed in a way that SwiftUI doesn't track changes (e.g., from an external object without proper @State or @Binding propagation), the system may not recognize that the sheet should be dismissed.

The Fix

Ensure the sheet's binding is properly managed and that the presentation mode is used in the correct context. Here's the corrected version:

struct ContentView: View {
    @State private var isSheetPresented = false

    var body: some View {
        Button("Show Sheet") {
            isSheetPresented = true
        }
        .sheet(isPresented: $isSheetPresented) {
            SheetView(isPresented: $isSheetPresented)
        }
    }
}

struct SheetView: View {
    @Binding var isPresented: Bool

    var body: some View {
        Button("Dismiss") {
            isPresented = false
        }
    }
}
// ✅ Fixed: Instead of relying solely on presentationMode, bind directly to the state controlling the sheet.

Alternative Approaches

  1. Using presentationMode with a custom environment binding: If you prefer to use presentationMode, ensure the sheet's content view is part of the same environment where the presentation context is active.

  2. Using @ObservedObject or @StateObject for shared state: You can manage the sheet's presentation state via a shared view model that both the parent and sheet view observe.

class SheetViewModel: ObservableObject {
    @Published var isPresented = false
}

// In ContentView:
@StateObject private var viewModel = SheetViewModel()

.sheet(isPresented: $viewModel.isPresented) {
    SheetView(viewModel: viewModel)
}

Affected iOS Versions

This behavior affects iOS 13 through iOS 15. While not officially "fixed", SwiftUI's behavior in iOS 16 improved with the introduction of NavigationStack and better presentation APIs, which can reduce reliance on presentationMode for dismissal.