SwiftUI Confirmation Dialogs

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.

Alert showing something went wrong, try again later and blue OK button

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:

Two buttons arranged vertically and presented from the bottom of the iPhone screen. Top button shows delete all items question in red, bottom button shows cancel in blue.

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.

Popover below a delete button showing delete all items?

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")
}

Dialog title is 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) { ... }
}

First action is text only label showing tell me more…