SwiftUI Tutorial: Adding Search Functionality to a List View (TodoList app)

Rizal Hilman
4 min readJul 20, 2023

--

SwiftUI .searchable() modifiers

In this tutorial, we will demonstrate the use of the .searchable modifier in SwiftUI by adding a search feature to our Todo List app. Users will be able to search for specific tasks or todos based on their titles. We'll walk you through the steps to implement this feature, building upon the Todo List project from a previous tutorial.

Prerequisites

Before proceeding with this tutorial, make sure you have completed the following tutorial, as we will be building upon the existing Todo List app: SwiftUI Tutorial: Displaying collection data with List View — Todolist App

If you haven’t completed the Todo List app yet, we recommend going through the above tutorial first.

Overview

In the Todo List app, we’ll add a search bar to the user interface, allowing users to easily find specific tasks by typing in keywords. As the user enters text into the search bar, the app will dynamically filter the todo items and display only those that match the search keyword.

Adding Search Bar User Interface

First, open ContentView.swift, where the main view of the Todo List app is defined. To store the user-typed keyword for searching, add a new @State variable:

// MARK: user typed keyword
@State var searchKeyword: String = ""

Next, let’s integrate the .searchable modifier into our List view and bind it to the searchKeyword variable:

List {
// List content...
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)

By adding the .searchable modifier to the List, we enable the search functionality and bind the search text to the searchKeyword variable.

This is our updated ContentView code:

struct ContentView: View {

// MARK: user typed keyword
@State var searchKeyword: String = ""

var body: some View {
NavigationView {
List {
ForEach(todos, id: \.self) { todo in
NavigationLink(destination: TodoDetailView(todo: todo)) {
HStack(alignment: .center) {
VStack(alignment: .leading) {
Text(todo.title)
.font(.title3)
Text(formatDate(todo.date))
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
StatusIndicator(status: todo.status)
}
}
}
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)

}
}

private func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: date)
}
}

Implementing Search Filtering

With the search bar in place, we can now implement the logic to filter the todo list based on the user’s search input. We need a new variable to hold the filtered result, but we don’t want to modify the original todos variable to preserve the original data. Below the searchKeyword state, add a new computed property called results:

var results: [Todo] {
return searchKeyword.isEmpty ? todos : todos.filter({ todo in
todo.title.contains(searchKeyword)
})
}

The results variable returns the filtered todos array. If the searchKeyword is empty, we show all todos. Otherwise, we use the filter method to find todos whose titles contain the searchKeyword.

Updating List Data Source

Now that we have the results variable containing the filtered todos, we need to update the List to use this data source. Replace todos with results in the ForEach loop:

ForEach(results, id: \.self) { todo in
// Todo item content...
}

With this change, the List will now display only the todos that match the search keyword, and it will automatically update as the user types in the search bar.

Final ContentView Code

Here’s the final code for the ContentView with the search functionality implemented:

import SwiftUI

struct ContentView: View {

// MARK: user typed keyword
@State var searchKeyword: String = ""

var results: [Todo] {
return searchKeyword.isEmpty ? todos : todos.filter({ todo in
todo.title.lowercased().contains(searchKeyword.lowercased())
})
}

var body: some View {
NavigationView {
List {
ForEach(results, id: \.self) { todo in
NavigationLink(destination: TodoDetailView(todo: todo)) {
HStack(alignment: .center) {
VStack(alignment: .leading) {
Text(todo.title)
.font(.title3)
Text(formatDate(todo.date))
.font(.subheadline)
.foregroundColor(.gray)
}
Spacer()
StatusIndicator(status: todo.status)
}
}
}
}
.listStyle(.inset)
.padding()
.navigationTitle("Todo List")
// MARK: Add searchable modifier
.searchable(text: $searchKeyword)
}
}

private func formatDate(_ date: Date) -> String {
let formatter = DateFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .short
return formatter.string(from: date)
}
}

With the above code, your Todo List app will now have a search bar that allows users to easily find tasks by their titles. As they type in the search bar, the list will be updated dynamically to display only the relevant todo items. This feature enhances the usability and user experience of the app, making it more efficient to manage tasks. Feel free to explore and customize the app further to suit your needs!

Finish Project on Github

https://github.com/drawrs/SwiftUI-Simple-TodoList/tree/searchable

--

--

Rizal Hilman

Tech Mentor at Apple Developer Academy - Batam | Apple Swift Certified Trainer | Apple Professional Learning Specialist | Apple Teacher | WWDC19 Winner