Display empty states with ContentUnavailableView in SwiftUI

Display empty states with ContentUnavailableView in SwiftUI

Learn how to use the ContentUnavailableView to represent empty states in a SwiftUI application.

If you've ever encountered an iOS app that fails to display content due to network issues or empty data sets you might have seen a "content unavailable" view.

This view was introduced in iOS 17 both in SwiftUI and UIKit to indicate that the content cannot be displayed.

It's typically displayed in the following scenarios:

  • When you have an empty list of elements
  • When the detail view of a NavigationSplitView has nothing selected
  • When a search doesn't return any results
  • When there is no internet connection

In this article, we'll take a closer look at when to use this view and how to use it correctly in SwiftUI.

Usage

In its most basic usage, SwiftUI's ContentUnavailableView presents a simple icon and label to indicate when content is not available.

ContentUnavailableView("No notes", systemImage: "doc.text")

Optionally you can add a description.

ContentUnavailableView(
    "No notes",
    systemImage: "doc.text",
    description: Text("You haven't created any notes yet.")
)

Notice that being the description a Text you can even customize its appearance, the font, the style, and more with the text and symbol modifiers.

ContentUnavailableView(
    "No notes",
    systemImage: "doc.text",
    description: Text(
        "You haven't created any notes yet."
    )
    .underline()
)

This is great when the detail view of a NavigationSplitView has nothing selected or when a search doesn't return any results.


When the content is unavailable because the user has yet to perform an action the ContentUnavailableView also presents the possibility of adding a call to action.

In the example below the user needs to create a note to be able to see it so we added a button to allow the user to do that.

ContentUnavailableView {
    Label("No notes", systemImage: "doc.text")
} description: {
    Text("You haven't created any notes yet.")
} actions: {
    Button {
        /// Function that creates a new note
    } label: {
        Label("Create a new note", systemImage: "plus")
    }
}

This specific initializer gives you more control over the title using views for each part of the ContentUnavailableView.


If you are presenting a ContentUnavailableView to represent the absence of results from a search action you can use the search(text:) type method to initialize one for you.

It creates a ContentUnavailableView that communicates to the user that the search had no results for their input text.

You can even specify the search text that returned no results.


NavigationSplitView {
    List(searchResults, selection: $selectedNoteId) { ... }
        .overlay {
            if searchResults.isEmpty {
                ContentUnavailableView.search(text: searchText)
            }
        }
        .navigationTitle("Notes")
        .searchable(text: $searchText)
    
} detail: {
    if let selectedNoteId {
        /// The view showing the details of the selected note
    } else {
        ContentUnavailableView("No Note Selected", systemImage: "doc.text", description: Text("Please select a note"))
}

The ContentUnavailableView is a useful feature for developers who want to provide a seamless and engaging user experience in their apps.

It's particularly helpful in situations where there are unsuccessful searches, unselected details in a NavigationSplitView, or no internet connectivity.

This view not only directly informs users about the absence of content but also integrates well with the operating system design, ensuring consistency with the intuitive style that iOS users expect.