How to add a search bar in SwiftUI

AsyncLearn
3 min readFeb 12, 2024

--

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:

  1. Creates an array of Employee, which will be our data source.
  2. 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.

iOS Simulator showing a list of employees being filtered when we enter the letter “A”

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:

  1. Uses the variable isActive to store a boolean value indicating whether we are filtering only active employees.
  2. If criteria is empty, it filters only by the active property.
  3. Otherwise, it filters by name and active.

Run the application to see the new functionality in action:

iOS Simulator showing a list of employees being filtered using text and indicating the type of employee

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/

--

--

AsyncLearn
AsyncLearn

Written by AsyncLearn

Stay up-to-date in the world of mobile applications with our specialised blog.

No responses yet