Presenting critical information in SwiftUI with alerts

Presenting critical information in SwiftUI with alerts

Learn how to create and use alerts within a SwiftUI app.

There are different ways to present information in a modal experience, one of which is through alerts. An alert interrupts the user with critical information they need immediately and presents different actions that can be triggered directly from the alert itself.

Use alerts for important messages, such as communicating errors, requesting confirmations (especially for destructive actions), or requesting permission.

SwiftUI provides several variations of the alert modifier, each designed for different use cases. By understanding these different alert presentations, you can choose the most appropriate approach for each situation in your SwiftUI applications, creating better user experiences that provide the right information at the right time.


The simplest form of alert uses a Boolean binding to control its presentation:

@State var isPresented: Bool = false

VStack {
    // UI code here
}
.alert("Alert Title", isPresented: $isPresented) {
    Button("Button1") {
        // Handle action
    }
    Button("Button2") {
        // Handle action
    }
}

This approach works well when you have a straightforward alert that doesn't require the display of dynamic content. The alert appears when isPresented value is true and automatically dismisses when the user taps one of the buttons in the alert or dismisses it.

For alerts that need additional explanation beyond the title, you can include a message closure:

.alert("Alert Title", isPresented: $isPresented) {
    Button("Button1") {
        // Handle action
    }
    Button("Button2") {
        // Handle action
    }
} message: {
    Text("Additional information about the alert")
}

The message appears below the title and provides context or instructions to help users understand the situation and make informed decisions.


When your alert needs to display or act upon specific data, use the presenting parameter. This approach is particularly useful when you want to confirm actions on specific items, such as deleting a document or canceling an order:

struct Document: Identifiable {
    var id: UUID = UUID()
    let name: String
    let size: String
}


VStack {
    // UI code here
}
.alert("Delete Document", isPresented: $isPresented, presenting: document) { document in
    Button("Delete", role: .destructive) {
        deleteDocument(document)
    }
    Button("Cancel", role: .cancel) {
        // Dismiss alert
    }
}

The presenting parameter ensures that the data passed to the alert remains consistent throughout the alert's lifecycle, even if the original data source changes before the user interacts with the alert. This is crucial for maintaining data integrity in confirmation dialogs.

You can also combine data presentation with custom messages to provide more context:

.alert("Delete Document", isPresented: $isPresented, presenting: document) { document in
    Button("Delete", role: .destructive) {
        deleteDocument(document)
    }
    
    Button("Cancel", role: .cancel) {
        // Dismiss alert
    }
} message: { document in
    Text("Are you sure you want to delete '\(document.name)'? This action cannot be undone.")
}

SwiftUI provides specialized alert modifiers for error handling. To use these, your error type must conform to LocalizedError. Here is an example:

enum MyError: LocalizedError {
    case network
    case unknown

    var errorDescription: String? {
        switch self {
        case .network: return "Network error occurred."
        case .unknown: return "Unknown error occurred."
        }
    }
    
    var recoverySuggestion: String? {
        switch self {
        case .network: return "Check your internet connection."
        case .unknown: return "Get in touch with us."
        }
    }
}

The basic error alert automatically uses the error's localizedDescription as the title:

.alert(isPresented: $isPresented, error: error) {
    Button("Retry") {
        // Handle retry action
    }
    Button("Cancel") {
        // Handle cancel action
    }
}

For a more detailed error presentation, you can access the error object in both the actions and message closures:

.alert(isPresented: $isPresented, error: error) { error in
    Button("Retry") {
        // Handle retry based on error type
    }
    Button("Cancel") {
        // Handle cancel action
    }
} message: { error in
    Text(error.recoverySuggestion ?? "Please try again later.")
}

This approach provides users with specific recovery suggestions based on the type of error that occurred.


Use alerts sparingly and only for critical situations that require immediate attention or a clear decision. Keep titles short and messages concise, with clear, action-oriented button labels instead of vague responses.

Always provide a meaningful default action and a safe way to cancel, assigning roles to your buttons, such as destructive or cancel, when appropriate. Limit the number of choices to avoid overwhelming the user, and prefer less intrusive UI elements, such as banners or inline messages, when the information doesn’t justify an interruption.