Skip to main content

Command Palette

Search for a command to run...

How to create unavailable content in SwiftUI using the ContentUnavailableView.

Published
4 min read
How to create unavailable content in SwiftUI using the ContentUnavailableView.

The video is in Portuguese but with English subtitles.

In modern application development, providing a clear and intuitive user experience is paramount. A key aspect of this is gracefully handling moments when content is not available. Whether it's due to a failed network request, an empty search result, or a feature that requires user data to be populated, presenting a blank screen can leave users confused. With the release of iOS 17, Apple introduced ContentUnavailableView, a powerful and flexible native SwiftUI component designed to elegantly manage these empty or unavailable states. 1

This article provides a comprehensive guide on how to use ContentUnavailableView to improve your SwiftUI applications, complete with practical code examples.

What is ContentUnavailableView?

ContentUnavailableView is a specialized view that provides a standardized interface for situations where a view’s primary content cannot be displayed. It typically consists of a label (often with an icon), a descriptive text, and optional action buttons. By using this native component, developers can save time and ensure a consistent user experience across the app and the entire Apple ecosystem. 2

Basic Implementation

The simplest way to use ContentUnavailableView is by providing a title and a system image. This is ideal for conveying a simple, clear message to the user.

For example, if you have a list of items that is currently empty, you can display a message as an overlay.

import SwiftUI

struct MyItemsView: View {
    @State private var items: [String] = []

    var body: some View {
        NavigationStack {
            List(items, id: \.self) { item in
                Text(item)
            }
            .navigationTitle("My Items")
            .overlay {
                if items.isEmpty {
                    ContentUnavailableView("No Items", systemImage: "tray.fill")
                }
            }
        }
    }
}

In this code, if the items array is empty, the List will be overlaid with a centered view showing the "tray.fill" icon and the text "No Items".

Adding Descriptions and Actions

To provide more context, you can add a description and even interactive actions, such as a "Refresh" button. This is particularly useful for scenarios like network errors, where you want to give the user a way to retry the action.

ContentUnavailableView offers a more advanced initializer that uses ViewBuilder closures for the label, description, and actions.

import SwiftUI

struct ProductsView: View {
    @State private var products: [String] = []
    @State private var hasError = true

    var body: some View {
        NavigationStack {
            if hasError {
                ContentUnavailableView {
                    Label("Connection Failed", systemImage: "wifi.slash")
                } description: {
                    Text("Please check your internet connection and try again.")
                        .multilineTextAlignment(.center)
                } actions: {
                    Button("Refresh") {
                        // Add logic to refetch data
                        fetchProducts()
                    }
                    .buttonStyle(.borderedProminent)
                }
            } else {
                List(products, id: \.self) { product in
                    Text(product)
                }
                .navigationTitle("Products")
            }
        }
        .onAppear(perform: fetchProducts)
    }

    func fetchProducts() {
        // Simulate a network request
        hasError = true // or false to show content
    }
}

This example demonstrates a common use case where an error state prompts the user with a clear explanation and a direct way to resolve the issue.

Handling Search Results

Another excellent use case for ContentUnavailableView is handling empty states in a searchable list. SwiftUI provides a convenient, pre-configured version specifically for this scenario: ContentUnavailableView.search.

This static instance automatically displays a relevant message, and if you provide the search text, it will even include the user's query in the description.

import SwiftUI

struct ContactsView: View {
    @State private var allContacts = ["Alice", "Bob", "Charlie", "David"]
    @State private var searchText = ""

    var searchResults: [String] {
        if searchText.isEmpty {
            return allContacts
        } else {
            return allContacts.filter { $0.lowercased().contains(searchText.lowercased()) }
        }
    }

    var body: some View {
        NavigationStack {
            List(searchResults, id: \.self) { contact in
                Text(contact)
            }
            .navigationTitle("Contacts")
            .searchable(text: $searchText)
            .overlay {
                if searchResults.isEmpty {
                    // Shows a message like "No results for \"query\""
                    ContentUnavailableView.search(text: searchText)
                }
            }
        }
    }
}

If the user searches for a term that yields no results, this view provides immediate and helpful feedback without any need for manual text formatting.

Conclusion

ContentUnavailableView is a valuable addition to the SwiftUI framework that simplifies the process of handling empty and error states. By leveraging its basic and advanced customization options, you can create more robust, user-friendly applications that communicate clearly and effectively in any scenario. Adopting this native component not only saves development time but also ensures your app feels polished and consistent with platform standards.