How to Handle Multiple Alerts in a Single View Using Enums
Following on from last month’s tutorial where
I talked about presenting multiple sheets in a single View, we can also do the same with alerts. This is something
I wish I knew when starting out with SwiftUI, as I first tried chaining multiple .alert()
only to find that only
one would work, followed by trying .background(EmptyView().alert(..) { .. })
. If you haven’t read the linked post
about handling multiple sheets, I highly recommend you check that out too.
While we could implement this without the below extension, we would have to make every definition of our
ActiveAlert
enum conform to Identifiable
, which feels like an unnecessary piece of code that is repeated
everywhere. This simple extension to View
creates a boolean binding based on whether our ActiveAlert
property has been set or is nil. We then leverage the existing alert(isPresented: )
view modifier that SwiftUI
provides to present our alert, providing the Alert
content and a callback that we can use inside our switch
statement in our view.
extension View {
public func alert<Value>(
using value: Binding<Value?>,
content: (Value) -> Alert
) -> some View {
let binding = Binding<Bool>(
get: { value.wrappedValue != nil },
set: { _ in value.wrappedValue = nil }
)
return alert(isPresented: binding) {
content(value.wrappedValue!)
}
}
}
Once that’s in place, it’s really easy to use across all of our views. Below is an example, where we define our
ActiveAlert
enum with the different kinds of alerts that we may present in this view, followed by some @State
that determines whether there is an active alert or not. We then use our custom view modifier alert(using: )
to
present our desired alert. You can copy this into your own app and see it in action!

struct ContentView: View {
enum ActiveAlert { case saved, delete, error(_ message: String) }
@State private var activeAlert: ActiveAlert?
var body: some View {
VStack {
Button("Show Saved Alert") {
activeAlert = .saved
}.padding()
Button("Show Delete Alert") {
activeAlert = .delete
}.padding()
Button("Show Error Alert 1") {
activeAlert = .error("Error 1")
}.padding()
Button("Show Error Alert 2") {
activeAlert = .error("Error 2")
}.padding()
}
.alert(using: $activeAlert) { alert in
switch alert {
case .saved:
return Alert(title: Text("Saved"), message: Text("Save is complete."))
case .delete:
return Alert(
title: Text("Deleting"),
message: Text("Are you sure you want to delete?"),
primaryButton: .default(Text("No")),
secondaryButton: .destructive(Text("Yes"))
)
case .error(let message):
return Alert(title: Text("Uh Oh"), message: Text(message))
}
}
}
}
Conclusion#
If this tutorial helped you in any way, I’d really appreciate a share on Twitter. You can reach out to me via Twitter if you have any questions, or to show me what you’ve been up to!