How to dismiss sheet in SwiftUI

⋅ 3 min read ⋅ SwiftUI Sheet

Table of Contents

A modal or sheet presentation is one of the core presentations in iOS. SwiftUI has many ways to dismiss a sheet view based on how you structure your view and the minimum iOS version you support.

There are three ways to dismiss a sheet in SwiftUI.

  1. Dismiss a sheet in the same view.
  2. Dismiss a sheet with @Binding.
  3. Dismiss a sheet with @Environment.

How to dismiss sheet in the same view

If a sheet view sits in the same view that presenting it, we can easily dismiss the sheet view by controlling the same binding value (isPresented) since it has access to the binding.

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

var body: some View {
Button("Detail") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
// Detail View
Button("Back to Main") {
isPresented = false
}
}
}
}

The detail view Button("Back to Main") can reach isPresented. So, we can easily dismiss it by setting isPresented to false to dismiss the sheet.

Set isPresented to false to dismiss a sheet.
Set isPresented to false to dismiss a sheet.

Most of the time, the view that you want to present might be too complicated to fit within a sheet closure. So, you probably separate it into another file.

Here we create a new DetailView that we want to present.

struct DetailView: View {
var body: some View {
Button("Back to Main") {

}
}
}

With a separate view like this, we no longer have access to the isPresented binding.

You have two ways to dismiss a sheet view that isn't on the same view.

  1. Dismiss a sheet with @Binding.
  2. Dismiss a sheet with @Environment.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

How to dismiss sheet with @Binding

One way to dismiss a presented view is to pass the isPresented binding to that view.

In this example, we add an isPresented binding to the DetailView.

struct DetailView: View {
// 1
@Binding var isPresented: Bool

var body: some View {
Button("Back to Main") {
// 2
isPresented = false
}
}
}

1 The DetailView accept the isPresented binding value.
2 Then, we use it to dismiss the sheet.

To use it, we pass an isPresented binding from the presenting view to a sheet view.

struct ContentView: View {
// 1
@State private var isPresented = false

var body: some View {
Button("Detail") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
// 2
DetailView(isPresented: $isPresented)
}
}
}

We pass down isPresented 1 from the presenting view to presented view, DetailView 2.

You can easily support sarunw.com by checking out this sponsor.

Sponsor sarunw.com and reach thousands of iOS developers.

Dismiss a sheet with @Environment

The other way for the view to dismiss itself is using environment value via the @Environment property wrapper.

Which environment value to use is depends on the iOS version you supported.

How to dismiss sheet in iOS 13/14

For a view to dismissing itself, we have to add @Environment(\.presentationMode) var presentationMode to a presented view.

We can dismiss the view by calling presentationMode.wrappedValue.dismiss().

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

var body: some View {
Button("Back to Main") {
presentationMode.wrappedValue.dismiss()
}
}
}

Then we can use DetailView as a sheet view without passing anything.

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

var body: some View {
Button("Detail") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
DetailView()
}
}
}

How to dismiss sheet in iOS 15

In iOS 15, Apple deprecated the presentationMode environment value, replacing it with a dismiss action (dismiss).

For a view to dismissing itself, we have to add @Environment(\.dismiss) private var dismiss to a presented view.

We can dismiss the view by calling dismiss().

struct DetailView: View {
@Environment(\.dismiss) var dismiss

var body: some View {
Button("Back to Main") {
dismiss()
}
}
}

Then we can use DetailView as a sheet view without passing anything.

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

var body: some View {
Button("Detail") {
isPresented = true
}
.sheet(isPresented: $isPresented) {
DetailView()
}
}
}

Read more article about SwiftUI, Sheet, or see all available topic

Enjoy the read?

If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.

Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.

If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.

Become a patron Buy me a coffee Tweet Share
Previous
How to scale custom fonts with Dynamic Type in SwiftUI

Learn how to make your custom font scale automatically like the system one.

Next
SwiftUI List Style examples

In this article, I will show you all 6 list styles you can use with SwiftUI List view in iOS.

← Home