How to: Add a search bar to NavigationView in SwiftUI
A fast way to add a search bar to your SwiftUI app with fuzzy search and NavigationView. (Bonus: becomeFirstResponder)
This year, at the top of the WWDC wish list, is for the SwiftUI team to add a search bar to the framework. There are so many ways to add search today from using a
TextField view to tapping into UIKit and using
UISearchBar via UIViewRepresentable.
Nevertheless, it’s a hassle, but I’m going to show you how you can add it relatively fast using SwiftUIX. SwiftUIX is a library full of various views missing in the SwiftUI standard library, one of being a search bar. They’ve conveniently added a modifier to
NavigationView that allows you to add a search bar and customize it with a few modifiers.
Under the hood it’s using view representable meaning it taps into UIKit like I mention above.
To install SwiftUIX, add the package to your project via SPM. The library doesn't support cococapods, but nothing stops you from forking it and adding your own podspec and using it as a development pod.
Next, we have to import our new package and then call the search bar modifier on our view. For this example, I will create a
List in a
NavigationView with the code below.
- Add the modifier to your outermost content view that returns a
- Add the
SearchBarand initialize it with the state for search text, editing, and callbacks.
- Did commit or tap done/enter on the keyboard.
- Did tap the cancel button on search bar.
SearchBar has two initializers that resemble other views in SwiftUI. We need to pass in some state for the text when the user is typing and editing, optionally callbacks when the user cancels or submits.
You can use the search bar alone too by adding it to your body if you don’t want to nest it in a NavigationView.
Now that we set up our search bar, how do we actually search a list of data? First, we can start by filtering our array as the user starts typing. It isn’t good UX to filter against an exact match, and we’ll want something better like a fuzzy search. We can write an algorithm that finds the search text as a substring within the array of names and return true when there’s a match.
Let's update the list to filter as the search text updates and lowercase the search text and name for better results. Also notice how the search text and friends array use
@State, which allows us to dynamically udate the list as it’s filtered from the search text.
Now, this looks good but let's clean it up a bit. We can overload an
== operator and take advantage of Swift keypaths to add some syntax sugar!
Keypaths allow us to reference the property with a shorthand syntax, and the overloaded operator can perform some checks and call search on the current name and search text.
Now we can update the
List to use our new overloaded operator, which makes it read nicer. As a performance boost, lets me added prefix for the first 30 results in our list too.
Now you were able to add a search bar to your SwiftUI project relatively fast. Hopefully, this becomes a thing of the past, and SwiftUI eventually adds first-party support for it!
Bonus: Do you need to make the search bar active and the first responder when the view is presented? We can do this with the library called introspect. Add it via SPM, then call the helper modifier for text field; — voilà! Now it’s the first responder and easily dismisses too, thanks again to SwiftUIX.