Using ContentUnavailableView to show an empty state in SwiftUI
From time to time we have to show an emptu state in a view. Mostly it’s when there is no data, there is some sort of an error, or there are no search results for the text that user entered. This is where ContentUnavailableView
comes in.
I will be honest, this cought me off guard. It’s a new SwiftUI view that comes with iOS 17
. I only noticed it lately and somehow missed it during WWDC 2023.
Basic usage of ContentUnavailableView
Right out of the box, the easiest applience for this is when user enters a text and app cant find any results. All you have to do is this:
1
2
3
var body: some View {
ContentUnavailableView.search
}
You can also specify a text. This should a text, that user has entered, for which you were unable to find data:
1
2
3
var body: some View {
ContentUnavailableView.search(text: "Banana")
}
Now since we are able to show it, let’s see how real example might look like:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
struct ContentView: View {
let fruits = ["Apple", "Watermellon", "Lemon", "Orange"]
@State var searchResults = [String]()
@State var searchText = ""
var body: some View {
NavigationStack {
List {
ForEach(searchResults, id: \.self) { fruit in
Text(fruit)
}
}
.navigationTitle("Fruits")
.searchable(text: $searchText)
.overlay {
// If search results are empty and user has entered the text
// We show our content unavailable view.
if searchResults.isEmpty && !searchText.isEmpty {
ContentUnavailableView.search(text: searchText)
}
}
.onChange(of: searchText) { _, newValue in
searchResults = fruits.filter {
$0.lowercased().contains(newValue.lowercased())
}
}
}
}
}
Now if you would run this code, search for a fruit that exists in fruits
array, you will see the fruit:
Or if you search for a fruit that does not exist, you will see our ContentUnavailableView
:
This is the most basic way of using ContentUnavailableView. Now let’s see how to customise it for other scenarios, not just search
Customizing ContentUnavailableView
So ContentUnavailableView
can also be used in other scenarios and represent different state when content is unavailable. We can customise ContentUnavailableView
using different initialiser.
We can pass a label
, description
and actions
to ContentUnavailableView
. With this, we can change the appearence of the View and even add actions. This helps in multiple scenarios. Even on network errors, etc.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
struct ContentView: View {
var body: some View {
ContentUnavailableView(label: {
Label("No Mail", systemImage: "tray.fill")
}, description: {
Text("New mails you receive will appear here.")
}, actions: {
Button(action: {
// Refresh emails
}) {
Text("Refresh")
}
})
}
}
Conclusion
Well, I can see myself using this in my own apps, especially since I always try to save time 😅. But if I would need to do something like this for a company, designs would probably not match to what ContentUnavailableView
offers and I would probably end up creating a custom EmptyStateView
which would match my app and would be way more flexible.
Anyways, have a great 2024 everyone!