How it works
DismissSearchAction is a callable structure that programmatically ends the current search interaction, clearing focus from the search field and dismissing any search-specific presentation that a searchable modifier installed. Reach for it when your own UI — a button, a row tap, a completed action — needs to take the user out of search mode rather than waiting for them to cancel manually. You never construct one yourself; SwiftUI vends a ready-made instance through the environment, and you invoke it like a function to trigger the dismissal.
Read the action from the environment with @Environment(\.dismissSearch)
A DismissSearchAction is only meaningful inside a view that lives under a search context, so SwiftUI supplies it through the environment rather than an initializer. Declare a property with
@Environment(\.dismissSearch) private var dismissSearchto bind the current action, asSearchResultsdoes. The value is always present, but it only has an effect when the surrounding scope is actually searching.Invoke the action as a function with dismissSearch()
DismissSearchAction conforms to the call-as-function pattern, meaning you trigger it by calling the bound value directly —
dismissSearch()— with no arguments and no return value. Here it runs inside theButton("Done")action, so tapping Done resigns the search field's focus and collapses the search presentation in one call.Establish the search context that the action acts on
The action has nothing to dismiss unless a search scope exists above it. The
.searchable(text: $query, prompt: "Search fruits")modifier onSearchResultsis what activates search and whatdismissSearch()later tears down; the boundquerystate stays intact, since dismissing search ends the interaction without erasing the typed text.Place the consuming view inside the searchable hierarchy
Because the environment value flows down the view tree, the view that calls the action must be a descendant of the view carrying
.searchable. In the exampleSearchResultsboth declares.searchableand reads\.dismissSearch, so itsButtonis correctly positioned to dismiss the search it owns.
print(query) line right before dismissSearch() in the Button("Done") action, type into the field, then tap Done to confirm the search dismisses while the entered text is preserved.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct DismissSearchActionDemo: View {
@State private var query = ""
var body: some View {
NavigationStack {
SearchResults()
.searchable(text: $query, prompt: "Search fruits")
.navigationTitle("Fruits")
}
}
}
struct SearchResults: View {
@Environment(\.dismissSearch) private var dismissSearch
var body: some View {
List {
Text("Apple")
Text("Banana")
Button("Done") {
dismissSearch()
}
}
.padding()
}
}