The confirmationDialog view modifier (SwiftUI Release 3, iOS 15+) presents a system dialog
before a dangerous action, such as deleting data. It adapts by size class: an action sheet in
compact widths and a popover in regular widths.
Presenting the Dialog
The modifier takes a title (a Text or LocalizedStringKey), a boolean binding that controls
presentation, and a ViewBuilder of text-only buttons for the actions.
struct ContentView: View {
@StateObject var viewModel = ViewModel()
@State private var confirmationShown = false
var body: some View {
List {
ForEach(viewModel.messages, id: \.self) { message in
Text(message)
.swipeActions {
Button(role: .destructive) {
confirmationShown = true
} label: {
Image(systemName: "trash")
}
}
.confirmationDialog("Are you sure?", isPresented: $confirmationShown) {
Button("Yes") {
withAnimation { viewModel.delete(message) }
}
}
}
}
}
}
SwiftUI adds a cancel button for you, and it dismisses the dialog as soon as the user taps any action. You never reset the binding to false yourself.
Roles, Default Action, and Ordering
Provide a role: .cancel button only to replace the default cancel label. The system may
reorder buttons by role and prominence; mark the default action with
.keyboardShortcut(.defaultAction) to give it the higher prominence.
.confirmationDialog("Are you sure?", isPresented: $confirmationShown) {
Button("Yes") {
withAnimation { viewModel.delete(message) }
}
.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
}
Title Visibility, Message, and Presented Data
titleVisibility takes automatic, visible, or hidden. A trailing message closure adds a
line under the title. The presenting: parameter passes a value into both closures, so the
dialog can name the item it is about to delete.
.confirmationDialog(
"Are you sure?",
isPresented: $confirmationShown,
titleVisibility: .visible,
presenting: message
) { message in
Button("Yes, delete: \(message)") {
withAnimation { viewModel.delete(message) }
}
.keyboardShortcut(.defaultAction)
Button("No", role: .cancel) {}
} message: { message in
Text(message)
}