Adding a search bar helps users quickly find items in a list. The searchable modifier makes it easy to add this feature in SwiftUI.
Search with searchable modifier in iOS Swift
Introduction
Syntax
iOS Swift
List(items, id: \.self) { item in
Text(item)
}
.searchable(text: $searchText, prompt: "Search items")The searchable modifier is added to a view like List or ScrollView.
You bind a @State string variable to text to track the search input.
Examples
iOS Swift
@State private var searchText = "" List(fruits, id: \.self) { fruit in Text(fruit) } .searchable(text: $searchText)
iOS Swift
@State private var searchText = "" List(countries, id: \.self) { country in Text(country) } .searchable(text: $searchText, prompt: "Find a country")
iOS Swift
@State private var searchText = "" ScrollView { VStack { ForEach(items.filter { searchText.isEmpty || $0.localizedCaseInsensitiveContains(searchText) }, id: \.self) { item in Text(item) } } } .searchable(text: $searchText)
Sample App
This app shows a list of fruits with a search bar on top. Typing in the search bar filters the list in real time.
iOS Swift
import SwiftUI struct ContentView: View { @State private var searchText = "" let fruits = ["Apple", "Banana", "Cherry", "Date", "Fig", "Grape"] var filteredFruits: [String] { if searchText.isEmpty { return fruits } else { return fruits.filter { $0.localizedCaseInsensitiveContains(searchText) } } } var body: some View { NavigationView { List(filteredFruits, id: \.self) { fruit in Text(fruit) } .navigationTitle("Fruits") .searchable(text: $searchText, prompt: "Search fruits") } } } @main struct MyApp: App { var body: some Scene { WindowGroup { ContentView() } } }
Important Notes
The searchable modifier works on iOS 15 and later.
Filtering the list based on the search text is done manually in your code.
Use localizedCaseInsensitiveContains for case-insensitive search.
Summary
The searchable modifier adds a search bar to lists or scroll views.
Bind a @State string to track user input.
Filter your data based on the search text to update the displayed list.
Practice
1. What does the
searchable modifier do in a SwiftUI view?easy
Solution
Step 1: Understand the purpose of
Thesearchablesearchablemodifier adds a search bar UI element to a list or scroll view.Step 2: Identify its effect on content
It allows users to type text to filter or search through the displayed content.Final Answer:
Adds a search bar to filter content in lists or scroll views. -> Option DQuick Check:
searchable = search bar added [OK]
Hint: searchable always adds a search bar UI [OK]
Common Mistakes:
- Thinking searchable sorts items automatically
- Confusing searchable with styling modifiers
- Assuming searchable removes items without filtering
2. Which of the following is the correct syntax to add a searchable modifier with a binding to a @State variable named
searchText?easy
Solution
Step 1: Recall the searchable syntax
The searchable modifier requires a binding to a string, written astext: $variable.Step 2: Match the correct binding syntax
Using$searchTextpasses the binding, so the correct syntax is.searchable(text: $searchText).Final Answer:
.searchable(text: $searchText) -> Option CQuick Check:
Binding uses $ with variable name [OK]
Hint: Use $ to bind @State variable in searchable [OK]
Common Mistakes:
- Omitting the text: label
- Not using $ for binding
- Passing variable without binding
3. Given this SwiftUI code snippet, what will be displayed when the user types "ap" in the search bar?
struct ContentView: View {
@State private var searchText = ""
let fruits = ["Apple", "Banana", "Grape", "Apricot"]
var filteredFruits: [String] {
if searchText.isEmpty { return fruits }
return fruits.filter { $0.lowercased().contains(searchText.lowercased()) }
}
var body: some View {
List(filteredFruits, id: \.self) { fruit in
Text(fruit)
}
.searchable(text: $searchText)
}
}medium
Solution
Step 1: Understand filtering logic
The filter checks if each fruit contains the search text "ap" ignoring case.Step 2: Apply filter to fruits list
"Apple" and "Apricot" contain "ap" (case-insensitive), "Banana" and "Grape" do not match exactly.Final Answer:
["Apple", "Apricot"] -> Option AQuick Check:
Filter by contains "ap" = Apple, Apricot [OK]
Hint: Filter checks contains ignoring case [OK]
Common Mistakes:
- Including fruits that don't contain "ap"
- Ignoring case sensitivity
- Returning full list regardless of search
4. Identify the error in this SwiftUI code using searchable:
struct ContentView: View {
@State var searchText = ""
let items = ["One", "Two", "Three"]
var filteredItems: [String] {
items.filter { $0.contains(searchText) }
}
var body: some View {
List(filteredItems, id: \.self) { item in
Text(item)
}
.searchable(text: searchText)
}
}medium
Solution
Step 1: Check searchable binding syntax
The searchable modifier requires a binding, so it must betext: $searchText, nottext: searchText.Step 2: Verify other code parts
filteredItems is computed correctly, List accepts array with id, and searchText should be @State.Final Answer:
Missing $ to bind searchText in searchable modifier. -> Option AQuick Check:
Binding needs $ prefix [OK]
Hint: Always use $ for @State binding in searchable [OK]
Common Mistakes:
- Forgetting $ in searchable binding
- Making filteredItems @State unnecessarily
- Confusing List requirements
5. You want to create a searchable list of contacts where typing filters by first or last name. Which code snippet correctly implements this behavior?
struct Contact: Identifiable {
let id = UUID()
let firstName: String
let lastName: String
}
struct ContentView: View {
@State private var searchText = ""
let contacts = [Contact(firstName: "John", lastName: "Doe"), Contact(firstName: "Jane", lastName: "Smith"), Contact(firstName: "Alice", lastName: "Johnson")]
var filteredContacts: [Contact] {
if searchText.isEmpty { return contacts }
return contacts.filter { contact in
contact.firstName.lowercased().contains(searchText.lowercased()) || contact.lastName.lowercased().contains(searchText.lowercased())
}
}
var body: some View {
List(filteredContacts) { contact in
Text("\(contact.firstName) \(contact.lastName)")
}
.searchable(text: $searchText)
}
}hard
Solution
Step 1: Analyze filtering logic
The filter checks if either firstName or lastName contains the search text, ignoring case.Step 2: Confirm UI updates with searchable
The searchable modifier binds to$searchText, so typing updates the filteredContacts list dynamically.Final Answer:
Filters contacts by first or last name ignoring case and updates list dynamically. -> Option BQuick Check:
Filter by first or last name, case-insensitive [OK]
Hint: Filter with OR condition and ignore case for full search [OK]
Common Mistakes:
- Filtering only by first name
- Not using lowercased() causing case sensitivity
- Forgetting to bind searchText with $
Recommended
Ready to prove it?
Pass the test and this pattern moves unknown
10 questions ~5 mineasy hard
