How to add a search bar in SwiftUI
A search bar can enhance the user experience in our applications by allowing them to find information quickly. Thanks to the searchable
modifier, we can easily add a search bar in SwiftUI. Let's explore an example:
Preparing the Data
First, create the structure we will need. In a new iOS project with SwiftUI, open ContentView.swift and place the following code just before the declaration of ContentView
:
struct Employee: Identifiable {
let id = UUID()
let name: String
var active: Bool = true
}
This structure will contain the data of the employees that we want to filter.
Now, inside ContentView
and before the body
property, add the following code:
// 1
private let employees = [
Employee(name: "Angela"),
Employee(name: "Pam", active: false),
Employee(name: "Dwight"),
Employee(name: "Jim", active: false),
Employee(name: "Michael", active: false),
Employee(name: "Oscar")
]
// 2
@State private var criteria = ""
This code does the following:
- Creates an array of
Employee
, which will be our data source. - Defines a state variable that will contain the search criteria.
Preparing the View
Inside the body
, replace the existing code with the following:
NavigationStack {
List {
ForEach(filteredItems) { employee in
Text(employee.name)
}
}
}
.searchable(text: $criteria, prompt: "Employee name")
With this code, we create a NavigationStack
containing a List
that will display all the employees contained in the filteredItems
variable. Additionally, we have added the searchable(text:placement:prompt:)
modifier, which takes care of including the search bar in the NavigationStack
.
You will see a compilation error; to fix it, add the filteredItems
variable. This is a computed variable that returns the employees taking into account the value of criteria
to filter them:
var filteredItems: [Employee] {
if criteria.isEmpty {
return employees
} else {
return employees.filter { $0.name.localizedCaseInsensitiveContains(criteria) }
}
}
If criteria
is empty, this code will return the complete list; otherwise, it will filter the employees based on the value of the name
property.
Run the project and enter the letter A in the search bar to see the functionality in action.
Adding Scopes
The search bar can be complemented using searchScopes(_:scopes:)
. With this modifier, we can refine the search criteria by allowing the user to indicate the search category.
Just below the declaration of Employee
, add the following enum
:
enum Scope: String, CaseIterable {
case active, inactive
}
Then, below the declaration of criteria
, add:
@State private var scope = Scope.active
We have added an enum
with the options we want to show and a state variable, scope
, to save the changes as indicated by the user. scope
defaults to Scope.active
, so the first time the list is shown, we can only view active employees.
Below .searchable(text:placement:prompt:)
, add the following code:
.searchScopes($scope) {
ForEach(Scope.allCases, id: \.self) { scope in
Text(scope.rawValue.capitalized)
}
}
This code adds searchScopes(_:scopes:)
, which allows us to specify the state variable that will store the desired scope.
For this to work, we must modify filteredItems
to take into account the value of scope
:
var filteredItems: [Employee] {
// 1
let isActive = scope == .active
if criteria.isEmpty {
// 2
return employees.filter { $0.active == isActive }
} else {
// 3
return employees.filter { $0.name.localizedCaseInsensitiveContains(criteria) && $0.active == isActive }
}
}
This code does the following:
- Uses the variable
isActive
to store a boolean value indicating whether we are filtering only active employees. - If
criteria
is empty, it filters only by theactive
property. - Otherwise, it filters by
name
andactive
.
Run the application to see the new functionality in action:
Other Considerations
If you want to react when the user presses the search
key on the keyboard, you can use the onSubmit(of:_:)
modifier, for example:
.onSubmit(of: .search, filterEmployees)
If you want to read the Spanish version of this article, you can find it here: https://asynclearn.com/blog/como-agregar-una-barra-de-busqueda-en-swiftui/