ContentUnavailableView is the standard empty-state view: an icon, a title, an optional
description, and optional actions. Use it as an overlay when a list or a search has nothing to
show.
Title, Image, Description
The simple initializers take a title, a system image, and optionally a description. Show the view
as an overlay on the list, gated on the empty condition.
List(store.products, id: \.self) { product in
Text(verbatim: product)
}
.navigationTitle("Products")
.overlay {
if store.products.isEmpty {
ContentUnavailableView(
"Connection issue",
systemImage: "wifi.slash",
description: Text("Check your internet connection")
)
}
}
Adding Actions
The ViewBuilder initializer takes label, description, and actions closures, so the empty state
can offer a way out.
ContentUnavailableView {
Label("Connection issue", systemImage: "wifi.slash")
} description: {
Text("Check your internet connection")
} actions: {
Button("Refresh") {
store.fetch()
}
}
The Built-In Search State
ContentUnavailableView.search is a predefined, localized "no results" view. It walks the view
hierarchy to find the search bar and puts the query text into its message.
.overlay {
if store.products.isEmpty {
ContentUnavailableView.search
}
}
.searchable(text: $store.query)
The gotcha: place searchable after the overlay in the modifier chain. Otherwise the view cannot
find the search bar and the message loses the query text. When the hierarchy does not cooperate,
pass the query yourself with ContentUnavailableView.search(text: store.query).