<!--
{
  "documentType" : "article",
  "framework" : "SwiftUI",
  "identifier" : "/documentation/SwiftUI/Managing-search-interface-activation",
  "metadataVersion" : "0.1.0",
  "role" : "article",
  "title" : "Managing search interface activation"
}
-->

# Managing search interface activation

Programmatically detect and dismiss a search field.

## Discussion

People activate a search field in your app by tapping or clicking it, after
which they can enter search terms. In many cases, your app only needs to react
to the corresponding changes in the search text values, which the interface
updates through the binding that you provide, as described in
[Performing a search operation](/documentation/SwiftUI/Performing-a-search-operation).

However, SwiftUI also provides controls that enable you to
programmatically manage the search interface. In particular, you can:

- Activate or deactivate the interface using a binding that you provide
  to the searchable modifier.
- Detect whether the interface is active by reading an environment value.
- Dismiss the interface by calling an action stored in the environment.
- Wait for a search submission event before starting to search.

### Control activation through a binding

You can control search interface activation programmatically by providing
the searchable modifier’s `isPresented` parameter with a [`Binding`](/documentation/SwiftUI/Binding) to a
Boolean value. For example, to present a sheet that appears with the search
interface already active, create a binding that starts as true:

```
struct SheetView: View {
    @State private var isPresented = true
    @State private var text = ""
  
    var body: some View {
        NavigationStack {
            SheetContent()
                .searchable(text: $text, isPresented: $isPresented)
        }
    }
}   
```

On iOS and macOS, SwiftUI focuses the search field when presenting search and
unfocuses the search field when dismissing search. The search field can also
lose focus while the search interface remains presented. For example, if your
search interface contains a list of text fields, someone might move focus to
one of the text fields without dismissing the interface.

### Detect search activation

If you need to know when the search interface is active, you can query the
environment’s [`isSearching`](/documentation/SwiftUI/EnvironmentValues/isSearching) property using the
[`Environment`](/documentation/SwiftUI/Environment) property wrapper. The following example shows a view that
updates the text it displays based on the state of the property:

```
struct SearchingExample: View {
    @State private var searchText = ""

    var body: some View {
        NavigationStack {
            SearchedView()
                .searchable(text: $searchText)
        }
    }
}

struct SearchedView: View {
    @Environment(\.isSearching) private var isSearching

    var body: some View {
        Text(isSearching ? "Searching" : "Not searching")
    }
}
```

When someone first taps or clicks in a search field, the `isSearching` property
becomes `true`. When they cancel the search operation, the property becomes
`false`. It also becomes `false` if you programmatically dismiss the
interface, as the next section describes.

Be sure to read the property from inside a view that’s wrapped, either directly
or indirectly, by one of the [`searchable(text:placement:prompt:)`](/documentation/SwiftUI/View/searchable(text:placement:prompt:))
view modifiers, like `SearchedView` in the above example. You won’t detect any
change in the property value if you read it from outside of that context, like
if you put it in the `SearchingExample` view.

### Dismiss the search interface

You can programmatically deactivate the interface using the environment’s
[`dismissSearch`](/documentation/SwiftUI/EnvironmentValues/dismissSearch) action. For example, consider a
view with a [`Button`](/documentation/SwiftUI/Button) that presents more information about the first matching
item from a collection:

```
struct ContentView: View {
    @State private var searchText = ""

    var body: some View {
        NavigationStack {
            SearchedView(searchText: searchText)
                .searchable(text: $searchText)
        }
    }
}

private struct SearchedView: View {
    var searchText: String

    let items = ["a", "b", "c"]
    var filteredItems: [String] { items.filter { $0 == searchText.lowercased() } }

    @State private var isPresented = false
    @Environment(\.dismissSearch) private var dismissSearch

    var body: some View {
        if let item = filteredItems.first {
            Button("Details about \(item)") {
                isPresented = true
            }
            .sheet(isPresented: $isPresented) {
                NavigationStack {
                    DetailView(item: item, dismissSearch: dismissSearch)
                }
            }
        }
    }
}
```

The button becomes visible only after someone enters search text that produces
a match. The button’s action shows a sheet that provides more information about
the item, including an Add button for adding the item to a stored list of items:

```
private struct DetailView: View {
    var item: String
    var dismissSearch: DismissSearchAction

    @Environment(\.dismiss) private var dismiss

    var body: some View {
        Text("Information about \(item).")
            .toolbar {
                Button("Add") {
                    // Store the item here...

                    dismiss()
                    dismissSearch()
                }
            }
    }
}
```

People can dismiss the sheet by dragging it down, effectively canceling the
operation, leaving the in-progress search interaction intact. Alternatively,
They can tap the Add button to store the item. Because people are likely
done with both the detail view and the search interaction at this point,
the button’s closure uses the [`dismiss`](/documentation/SwiftUI/EnvironmentValues/dismiss) property to
dismiss the sheet, and the [`dismissSearch`](/documentation/SwiftUI/EnvironmentValues/dismissSearch) property to
reset the search field.

As with the `isSearching` property, be sure to only read `dismissSearch`
from within the hierarchy of a searchable view modifier. Calling the action has
no effect if you read it from the environment outside of that context. The
above example reads the action from `SearchedView`, and passes that into the
sheet, because the sheet has its own environment. The action also has no effect
if the search interface isn’t active.

### React to search submission

To specify an action that SwiftUI invokes when someone submits the
search query (by pressing the Return key), add the [`onSubmit(of:_:)`](/documentation/SwiftUI/View/onSubmit(of:_:))
modifier:

```
SearchedView()
    .searchable(text: $searchText)
    .onSubmit(of: .search) {
        submitCurrentSearchQuery()
    }
```

Depending your app’s structure, you can use search submission in different
ways. For example, you can take that opportunity to look for substrings
among the search query string that you can convert into tokens. Alternatively,
for a search operation that’s very slow, perhaps because it requires a network
access, you can wait for a submission event before performing a search.

---

Copyright &copy; 2026 Apple Inc. All rights reserved. | [Terms of Use](https://www.apple.com/legal/internet-services/terms/site.html) | [Privacy Policy](https://www.apple.com/privacy/privacy-policy)