In iOS 15, SwiftUI added a convenient view modifier to present a confirmation dialog to the user.
Sheets, Alerts and Confirmations
SwiftUI provides a generic sheet and a more specific alert for presenting dialog views to the user. The Apple iOS Human Interface Guidelines recommend you use an alert to tell the user something important has happened.
When you need to present choices related to an action the user is taking prefer to use an action sheet. When the action is destructive or undoable present a confirmation dialog to ask the user to confirm or cancel the action.
Alert Views
In iOS 15, you present an alert with a view modifier:
@State private var isPresentingAlert: Bool = false
var body: some View {
Button("Save") {
if !store.save()
isPresentingAlert = true
}
}
.alert("Something went wrong, try again later",
isPresented: $isPresentingAlert) {
}
}
In common with sheets, you use a binding to a boolean which when set to true triggers the system to present the alert. The system presents the alert modally in the center of the screen. If you don’t add any actions the system provides a default “OK” action. All actions dismiss the alert for you.
Confirmation Dialogs
In iOS 15, SwiftUI added the confirmation dialog view to ask the user for confirmation. For example, if I have a button that will delete all items:
struct DeleteButton: View {
@EnvironmentObject var store: Store
@State private var isPresentingConfirm: Bool = false
var body: some View {
Button("Delete", role: .destructive) {
isPresentingConfirm = true
}
.confirmationDialog("Are you sure?",
isPresented: $isPresentingConfirm) {
Button("Delete all items?", role: .destructive) {
store.deleteAll()
}
}
}
}
I’ve added the .destructive
role to the button which causes the system to highlight it in red:
The confirmation dialog has a couple of advantages over a generic sheet:
- You do not need to add a cancel button. The confirmation dialog includes a standard dismiss action by default.
- All actions in the confirmation dialog dismiss the dialog. As with an alert, you do not need to manually dismiss the dialog by setting the boolean state variable to false.
On an iPhone (and compact size classes) the system shows the dialog as a sheet that slides up from the bottom. On an iPad (regular size classes) it’s shown as a popover without a cancel button. A user can dismiss the dialog, cancelling the action, by tapping outside the dialog.
Adding a Message
You can include a message in the dialog:
.confirmationDialog("Are you sure?",
isPresented: $isPresentingConfirm) {
Button("Delete all items?", role: .destructive) { ...}
} message: {
Text("You cannot undo this action")
}
Text Only Controls
On iOS, tvOS and watchOS the buttons you add to the dialog only support text labels. If you include an image it’s ignored:
.confirmationDialog("Are you sure?",
isPresented: $isPresentingConfirm) {
Button { ...
} label: {
Label("Tell me more...",
systemImage: "questionmark.circle")
}
Button("Delete all?", role: .destructive) { ... }
}