A modal view is a view that shows up on top of the currently displayed view and that prevents interaction with the underlying view. The modal view is used to capture user input or display additional information without navigating away from the current screen. Once a modal view appears, it needs to be dismissed before interaction is possible with the rest of the application.
Showing a modal sheet (iOS 15+)
Sheets are used to display a view on top of another one, and they can be dismissed by dragging them down or programmatically. You need a Boolean
that controls whether the sheet is presented.
struct SheetView: View { @Environment(\.dismiss) var dismiss var body: some View { Button("Dismiss") { dismiss() } } } struct ContentView: View { @State var isVisible = false var body: some View { Button("Show") { isVisible.toggle() } .sheet(isPresented: $isVisible) { SheetView() } } }
Here the @State
property is used to control the presentation of the sheet. It is initialized to false
, meaning the sheet is not shown initially.
If you want your modal sheet to cover a view entirely and not be dismissible by dragging, you can use the .fullScreenCover
modifier.
struct ContentView: View { @State var isVisible = false var body: some View { Button("Show") { isVisible.toggle() } .fullScreenCover(isPresented: $isVisible, content: SheetView.init) } }
Showing alerts (iOS 15+)
To show an alert the approach is similar to that used for sheets: you need a Boolean
to decide whether the alert is shown, and then you attach the alert()
modifier to the main view and include all the buttons you need inside the alert.
struct ContentView: View { @State var isVisible = false var body: some View { Button("Show") { isVisible.toggle() } .alert("Here is the Alert", isPresented: $isVisible) { Button("OK", role: .cancel) { } } } }
The popover (iOS 13.0+)
The popover was originally an iPad-only view presented modally and originates from the point where it is invoked, generally on a button.
The popover
function in SwiftUI is a view modifier. It takes four main parameters:
isPresented
. A binding variable to control the visibility of the popover.attachmentAnchor
. Specifies where the popover anchors. It defaults to the bounds of the target view.arrowEdge
. Indicates the edge where the popover’s arrow points. It defaults to the top edge.content
. A closure that generates the content inside the popover.popover
modifier returns a modified view that shows the popover whenever isPresented
is set to true.
struct ContentView: View { @State var isVisible = false var body: some View { Button("Show") { isVisible.toggle() } .popover(isPresented: $isVisible) { Text("Here is the Popover") .padding() } } }
For an iPhone, you will get the very same behavior and appearance as a modal sheet.
Presentation detents (iOS 16+)
The .presentationDetents
modifier allows you to present a modal sheet which shows up only partially to cover the screen, in steps you can specify.
If you don’t specify any detent, the default is going to be .large
. You can specify .medium
(half screen) or .large
(full length) – use an array of floating point values, a floating point fraction of the available height (.fraction()
), or give a precise height in points with .height()
. If you are developing a horizontal app, you should provide a button to dismiss the sheet. If you want to display a drag indicator, use the .presentationDragIndicator(.visible)
modifier to show it.
struct ContentView: View { @State var isVisible = false var body: some View { Button("Show") { isVisible.toggle() } .sheet(isPresented: $isVisible) { SheetView() .presentationDetents([.height(250)]) .presentationDragIndicator(.visible) } } }