> ## Documentation Index
> Fetch the complete documentation index at: https://algolia.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get started with SwiftUI

> Build an InstantSearch iOS page from start to finish using SwiftUI.

export const SearchQuery = () => <Tooltip tip="The text users enter into a search box. In the Search API, this corresponds to the query parameter. A search query is often used with filters, facets, and other parameters, but these aren't part of the query text itself.">
    search query
  </Tooltip>;

export const Records = () => <Tooltip tip="A record is a searchable object in an Algolia index. Each record consists of named attributes." cta="Algolia records" href="/doc/guides/sending-and-managing-data/prepare-your-data#algolia-records">
    records
  </Tooltip>;

export const Filter = () => <Tooltip tip="A filter is a condition that limits which records Algolia returns. Filters often use one or more facet-value pairs, such as brand:Apple AND color:red. You can also filter by numeric values, dates, tags, booleans, or geographic constraints." cta="Filtering" href="/doc/guides/managing-results/refine-results/faceting">
    filter
  </Tooltip>;

export const Facet = () => <Tooltip tip="An attribute in your records that lets users filter or group results (for example, by color, brand, or price)." cta="Faceting" href="/doc/guides/managing-results/refine-results/faceting">
    facet
  </Tooltip>;

export const ApplicationID = () => <Tooltip tip="A unique alphanumeric string that identifies an Algolia application." cta="Application ID (dashboard)" href="https://dashboard.algolia.com/account/api-keys">
    application ID
  </Tooltip>;

export const APIKey = () => <Tooltip tip="An alphanumeric string that controls access to the Algolia APIs. It defines what actions are allowed, such as searching an index or adding new records." cta="API key" href="/doc/guides/security/api-keys">
    API key
  </Tooltip>;

export const Index = () => <Tooltip tip="An Algolia index is a searchable dataset that consists of records and configuration settings. These settings define how the records are searched and ranked.">
    index
  </Tooltip>;

<div className="not-prose algolia-flavor-switcher">
  <div className="afs-dropdown">
    <div className="afs-trigger" role="button" tabIndex="0" aria-haspopup="listbox">
      <span className="afs-current">iOS</span>

      <svg className="afs-chevron lucide lucide-chevron-down" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
        <path d="m6 9 6 6 6-6" />
      </svg>
    </div>

    <ul className="afs-menu" role="listbox">
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/guides/building-search-ui/getting-started/how-to/declarative/ios"><span className="afs-option-name">iOS</span><span className="afs-option-lib">InstantSearch iOS</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/guides/building-search-ui/getting-started/how-to/declarative/android"><span className="afs-option-name">Android</span><span className="afs-option-lib">InstantSearch Android</span></a></li>
    </ul>
  </div>
</div>

This guide describes how to start a SwiftUI project with InstantSearch iOS and create a full search experience from scratch.

This guide walks you through the steps needed to create a full InstantSearch Android experience from scratch.

It includes:

* A search box for users to type queries
* A list to display search results
* A <Facet /> list to <Filter /> results
* Statistics about the search

## Before you begin

To use InstantSearch, you need an Algolia account.
[Sign up](https://dashboard.algolia.com/users/sign_up) for a new account or use the following credentials
(which include a pre-loaded dataset of products appropriate for this guide):

* <ApplicationID />: `latency`
* Search <APIKey />: `1f6fd3a6fb973cb08419fe7d288fa4db`

- <Index /> name: `bestbuy`

### Create a new project

In Xcode, create a new Project:

Open Xcode, and select `File -> New -> Project` in the menu bar.

<img src="https://mintcdn.com/algolia/n_gdBwT_QFZcudWB/doc/guides/building-search-ui/getting-started/how-to/declarative/project-creation.png?fit=max&auto=format&n=n_gdBwT_QFZcudWB&q=85&s=14b1583c22db11fed58ab5bfb9b18aaa" alt="Screenshot of the Xcode 'File' menu with the 'New' sub-menu open, highlighting the 'Project' option." width="1324" height="1360" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/project-creation.png" />

Select `iOS -> App` template and click `Next`.

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/project-template-selection.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=9fc83b72ebe3e0087834f0df8bb40a39" alt="Screenshot of a project template selection dialog with the 'App' template highlighted under the iOS category." width="1462" height="1041" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/project-template-selection.png" />

Give your app a name.
Make sure that you have selected `SwiftUI` option in the `Interface` field and click `Next`.

<img src="https://mintcdn.com/algolia/n_gdBwT_QFZcudWB/doc/guides/building-search-ui/getting-started/how-to/declarative/project-name-input.png?fit=max&auto=format&n=n_gdBwT_QFZcudWB&q=85&s=ea0392cd08e85d50a582392c998f3440" alt="Screenshot of a project setup dialog with the 'Product Name' field filled with 'AlgoliaSwiftUI' and a blue 'Next' button at the bottom right." width="732" height="521" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/project-name-input.png" />

You should see the `ContentView.swift` file opened with a `Hello World` project and the live preview canvas.

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/swiftui-helloworld.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=2c4d6fd71cf956e30ea511db904ae46c" alt="Screenshot of a SwiftUI project in Xcode showing the 'ContentView.swift' file with code and a preview of a phone displaying 'Hello, world!'." width="1202" height="1196" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/swiftui-helloworld.png" />

### Add project dependencies

This tutorial uses [Swift Package Manager](https://swift.org/package-manager) to integrate the InstantSearch library.
If you prefer to use another dependency manager (`Cocoapods`), check out the corresponding installation guides for [InstantSearch](https://github.com/algolia/instantsearch-ios#cocoapods).

In the menu bar select `File -> Swift Packages -> Add Package Dependency`.

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/spm-xcode-menu.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=38569ebbe1d48260e6b8e98e8be82f0b" alt="SPM Xcode menu" width="1332" height="1336" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/spm-xcode-menu.png" />

Paste the GitHub link for the InstantSearch library: [`https://github.com/algolia/instantsearch-ios`](https://github.com/algolia/instantsearch-ios)

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/spm-url-input.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=ee80ab8c537c1fe778c678c3ca84284d" alt="SPM URL input" width="1462" height="862" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/spm-url-input.png" />

Pick the latest library version on the next screen, and select the `InstantSearchSwiftUI` product from the following list:

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/spm-products-list.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=ba250a2cc208c6cc19620008a55933eb" alt="Screenshot of a dialog selecting 'InstantSearchSwiftUI' for 'SearchApp' with 'Add Package' and 'Cancel' buttons." width="1330" height="622" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/spm-products-list.png" />

The InstantSearch dependency is installed and you're all set to work on your app.

## Implementation

Start by creating a classic search interface with search box and results list. In your Xcode project, open the `ContentView.swift` file and import the `InstantSearch` library.

```swift Swift icon=code theme={"system"}
import InstantSearchSwiftUI
```

### Define your record structure

Define a structure that represent <Records /> in your index.
For simplicity's sake, the structure only provides the name of the product.
It must conform to the `Codable` protocol to work with InstantSearch.
Add the following structure definition to the `ContentView.swift` file:

```swift Swift icon=code theme={"system"}
struct StockItem: Codable {
  let name: String
}
```

### Business logic

Add the `AlgoliaController` class containing the InstantSearch business logic components to the `ContentView.swift` file.

You need three components coupled with the corresponding UI controllers for the basic search experience:

* `HitsSearcher` performs search requests and obtains search results.
* `SearchBoxInteractor` handles a textual <SearchQuery /> input and triggers search requests when needed.
* `HitsInteractor` stores hits and manages the pagination logic.

The `setupConnections` method establishes the connections between these components and their UI controllers to make them work together seamlessly.

```swift Swift icon=code theme={"system"}
class AlgoliaController {

  let searcher: HitsSearcher

  let searchBoxInteractor: SearchBoxInteractor
  let searchBoxController: SearchBoxObservableController

  let hitsInteractor: HitsInteractor<StockItem>
  let hitsController: HitsObservableController<StockItem>

  init() {
    self.searcher = try! HitsSearcher(appID: "latency",
                                      apiKey: "1f6fd3a6fb973cb08419fe7d288fa4db",
                                      indexName: "bestbuy")
    self.searchBoxInteractor = .init()
    self.searchBoxController = .init()
    self.hitsInteractor = .init()
    self.hitsController = .init()
    setupConnections()
  }

  func setupConnections() {
    searchBoxInteractor.connectSearcher(searcher)
    searchBoxInteractor.connectController(searchBoxController)
    hitsInteractor.connectSearcher(searcher)
    hitsInteractor.connectController(hitsController)
  }

}
```

### UI

<Steps>
  <Step title="Declare observable controllers">
    Add `SearchBoxObservableController` and `HitsObservableController` properties to the `ContentView` structure with an `@ObservedObject` property wrapper, so the view is automatically notified when the state of the search text or the hits list changed.

    ```swift Swift icon=code theme={"system"}
    struct ContentView: View {

      @ObservedObject var searchBoxController: SearchBoxObservableController
      @ObservedObject var hitsController: HitsObservableController<StockItem>

      var body: some View {
          Text("Hello, world!")
              .padding()
      }

    }
    ```
  </Step>

  <Step title="Add state for search box editing">
    Add the `isEditing` property that binds the editing state of the search box.

    ```swift Swift icon=code theme={"system"}
    struct ContentView: View {

      @ObservedObject var searchBoxController: SearchBoxObservableController
      @ObservedObject var hitsController: HitsObservableController<StockItem>

      @State private var isEditing = false

      var body: some View {
          Text("Hello, world!")
              .padding()
      }

    }
    ```
  </Step>

  <Step title="Add search box to the view body">
    Replace the "Hello world!" text view with a vertical stack containing the `SearchBar` configured with `SearchBoxObservableController` properties and `isEditing` state binding.

    ```swift Swift icon=code theme={"system"}
    var body: some View {
      VStack(spacing: 7) {
        SearchBar(text: $searchBoxController.query,
                  isEditing: $isEditing,
                  onSubmit: searchBoxController.submit)
      }
    }
    ```

    From iOS 15, you can use the [`searchable`](https://developer.apple.com/documentation/swiftui/view-search) modifier to add a system search field.

    <Note>
      Embed your search view into the `NavigationView` to ensure the search input field appears.
    </Note>

    The body of your view will look as follows:

    ```swift Swift icon=code theme={"system"}
    var body: some View {
      VStack(spacing: 7) {
      }.searchable(text: $searchBoxController.query)
    }
    ```

    The following steps rely on an explicit `SearchBar` view (as a more versatile approach).
  </Step>

  <Step title="Display search results with a hits list component">
    Insert the `HitsList` component configured with `HitsObservableController` and a closure constructing the hit row.
    The hit row is represented by a vertical stack with a text block presenting the name of the item and a `Divider`.

    ```swift Swift icon=code theme={"system"}
    var body: some View {
      VStack(spacing: 7) {
        SearchBar(text: $searchBoxController.query,
                  isEditing: $isEditing,
                  onSubmit: searchBoxController.submit)
        HitsList(hitsController) { hit, _ in
          VStack(alignment: .leading, spacing: 10) {
            Text(hit?.name ?? "")
              .padding(.all, 10)
            Divider()
          }
        }
      }
    }
    ```
  </Step>

  <Step title="Add no results view and navigation title">
    Complete your search experience with a `noResults` trailing closure in the `HitsList`, that constructs the view presented in case of an empty result set, and add the `navigationBarTitle` string to show the navigation header on top of you search screen.

    ```swift Swift icon=code theme={"system"}
    var body: some View {
      VStack(spacing: 7) {
        SearchBar(text: $searchBoxController.query,
                  isEditing: $isEditing,
                  onSubmit: searchBoxController.submit)
        HitsList(hitsController) { (hit, _) in
          VStack(alignment: .leading, spacing: 10) {
            Text(hit?.name ?? "")
              .padding(.all, 10)
            Divider()
          }
        } noResults: {
          Text("No Results")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
      }
      .navigationBarTitle("Algolia & SwiftUI")
    }
    ```
  </Step>

  <Step title="Connect business logic to the UI">
    Try out the search experience in the live preview.
    Add a static instance of the `AlgoliaController` in the `PreviewProvider`.
    Then, in the `previews` declaration, instantiate the `ContentView` with the UI controller references in the `AlgoliaController` class, and embed it in the `NavigationView`.
    Launch the initial search inside the `onAppear` closure of the `NavigationView`.
    The resulting `ContentView_Previews` structure content should look as follows:

    ```swift Swift icon=code theme={"system"}
    struct ContentView_Previews: PreviewProvider {

      static let algoliaController = AlgoliaController()

      static var previews: some View {
        NavigationView {
          ContentView(searchBoxController: algoliaController.searchBoxController,
                      hitsController: algoliaController.hitsController)
        }.onAppear {
          algoliaController.searcher.search()
        }
      }

    }
    ```
  </Step>
</Steps>

### Preview

Launch your preview to see the basic search experience in action.
You should see that the results are changing on each key stroke.

<Columns cols={2}>
  <img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/search-basic-input.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=baeb11ee9390804ce616cfc74ece9568" alt="Screenshot of a mobile app with a search box showing 'Sony' and a list of Sony products below." style={{maxWidth:"300px"}} className="no-shadow" width="724" height="1420" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/search-basic-input.png" />

  <img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/search-basic-noresults.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=fa5c6c1e79158b025395345788ddfa6a" alt="Screenshot of a phone displaying a search interface with the query 'Abcde' in a search box, showing 'No Results' below." style={{maxWidth:"300px"}} className="no-shadow" width="724" height="1420" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/search-basic-noresults.png" />
</Columns>

### Add statistics

To make the search experience more user-friendly, you can give more context about the search results to your users.
You can do this with different InstantSearch modules.

<Steps>
  <Step title="Connect a statistics controller">
    This component shows the hit count and the request processing time.
    This gives users a complete understanding of their search, without the need for extra interaction.
    Then create a `StatsInteractor`, which extracts the metadata from the search response, and provides an interface to present it to users.
    Add `StatsInteractor` and `StatsTextObservableController` to `AlgoliaController` and connect the `StatsInteractor` to the `Searcher` in the `setupConnections` method.
    Complete the `setupConnections` method of the `PreviewProvider` with the connection between the `StatsInteractor` and the `StatsTextObservableController`.

    ```swift Swift icon=code theme={"system"}
    class AlgoliaController {

      let searcher: HitsSearcher

      let searchBoxInteractor: SearchBoxInteractor
      let searchBoxController: SearchBoxObservableController

      let hitsInteractor: HitsInteractor<StockItem>
      let hitsController: HitsObservableController<StockItem>

      let statsInteractor: StatsInteractor
      let statsController: StatsTextObservableController

      init() {
        self.searcher = try! HitsSearcher(appID: "latency",
                                          apiKey: "1f6fd3a6fb973cb08419fe7d288fa4db",
                                          indexName: "bestbuy")
        self.searchBoxInteractor = .init()
        self.hitsInteractor = .init()
        self.statsInteractor = .init()
        self.searchBoxController = .init()
        self.hitsController = .init()
        self.statsController = .init()
        setupConnections()
      }

      func setupConnections() {
        searchBoxInteractor.connectSearcher(searcher)
        searchBoxInteractor.connectController(searchBoxController)
        hitsInteractor.connectSearcher(searcher)
        hitsInteractor.connectController(hitsController)
        statsInteractor.connectSearcher(searcher)
        statsInteractor.connectController(statsController)
      }

    }
    ```
  </Step>

  <Step title="Show search statistics in the view">
    The `StatsInteractor` receives the search statistics now, but doesn't display it yet.

    Add `StatsTextObservableController` property to the `ContentView` and add the `Text` with its `stats` property into the stack in the middle of the `SearchBar` and the `HitsList`.

    ```swift Swift icon=code theme={"system"}
    struct ContentView: View {

      @ObservedObject var searchBoxController: SearchBoxObservableController
      @ObservedObject var hitsController: HitsObservableController<StockItem>
      @ObservedObject var statsController: StatsTextObservableController

      @State private var isEditing = false

      var body: some View {
        VStack(spacing: 7) {
          SearchBar(text: $searchBoxController.query,
                    isEditing: $isEditing,
                    onSubmit: searchBoxController.submit)
          Text(statsController.stats)
            .fontWeight(.medium)
          HitsList(hitsController) { (hit, _) in
            VStack(alignment: .leading, spacing: 10) {
              Text(hit?.name ?? "")
                .padding(.all, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
              Divider()
            }
          } noResults: {
            Text("No Results")
              .frame(maxWidth: .infinity, maxHeight: .infinity)
          }
        }
        .navigationBarTitle("Algolia & SwiftUI")
      }

    }
    ```
  </Step>

  <Step title="Update preview with statistics controller">
    Alter the `PreviewProvider` structure by adding a `StatsTextObservableController` in the `ContentView` initializer.

    ```swift Swift icon=code theme={"system"}
    struct ContentView_Previews: PreviewProvider {

      static let algoliaController = AlgoliaController()

      static var previews: some View {
        NavigationView {
          ContentView(searchBoxController: algoliaController.searchBoxController,
                      hitsController: algoliaController.hitsController,
                      statsController: algoliaController.statsController)
        }.onAppear {
          algoliaController.searcher.search()
        }
      }

    }
    ```
  </Step>
</Steps>

Update your live preview.
You should now see updated results *and* an updated hit count on each keystroke.

<img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/search-stats.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=336adaf6ca726c6dc896a6e4722d058d" alt="Screenshot of a phone showing search results for 'Algolia and SwiftUI' with items like 'Sony - PlayStation 4 (500GB)' and 'Apple® - iPad® mini Wi-Fi - 16GB - White/Silver'." style={{maxWidth:"300px"}} className="no-shadow" width="726" height="1420" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/search-stats.png" />

### Filter your results

With your app, you can search more than 10,000 products. However, you don't want to scroll to the bottom of the list to find the exact product you're looking for. One can more accurately filter the results by making use of the `RefinementList` components. This section explains how to build a filter that allows to filter products by their category.

1. Add a `FilterState` component to the `AlgoliaController`. This component provides a convenient way to manage the state of your filters. Add the `manufacturer` refinement attribute.
2. Add the `FacetListInteractor`, which stores the list of facets retrieved with search results.
3. Add the connections between `HitsSearcher`, `FilterState` and `FacetListInteractor` in the `setupConnections` method.
   Complete the `setupConnections` method of the `PreviewProvider` with the connection between the `FacetListInteractor` and the `FacetListObservableController`. To improve the user experience, the connection includes the `FacetListPresenter` parameter that pins the selected facets to the top of the list and uses facet count value as the second ranking criteria, so that the facets with the most hits show up higher.

```swift Swift icon=code expandable theme={"system"}
class AlgoliaController {

  let searcher: HitsSearcher

  let searchBoxInteractor: SearchBoxInteractor
  let searchBoxController: SearchBoxObservableController

  let hitsInteractor: HitsInteractor<StockItem>
  let hitsController: HitsObservableController<StockItem>

  let statsInteractor: StatsInteractor
  let statsController: StatsTextObservableController

  let filterState: FilterState

  let facetListInteractor: FacetListInteractor
  let facetListController: FacetListObservableController

  init() {
    self.searcher = try! HitsSearcher(appID: "latency",
                                      apiKey: "1f6fd3a6fb973cb08419fe7d288fa4db",
                                      indexName: "bestbuy")
    self.searchBoxInteractor = .init()
    self.searchBoxController = .init()
    self.hitsInteractor = .init()
    self.hitsController = .init()
    self.statsInteractor = .init()
    self.statsController = .init()
    self.filterState = .init()
    self.facetListInteractor = .init()
    self.facetListController = .init()
    setupConnections()
  }

  func setupConnections() {
    searchBoxInteractor.connectSearcher(searcher)
    searchBoxInteractor.connectController(searchBoxController)
    hitsInteractor.connectSearcher(searcher)
    hitsInteractor.connectController(hitsController)
    statsInteractor.connectSearcher(searcher)
    statsInteractor.connectController(statsController)
    searcher.connectFilterState(filterState)
    facetListInteractor.connectSearcher(searcher, with: "manufacturer")
    facetListInteractor.connectFilterState(filterState, with: "manufacturer", operator: .or)
    facetListInteractor.connectController(facetListController, with: FacetListPresenter(sortBy: [.isRefined, .count(order: .descending)]))
  }

}
```

In the `ContentView` add a new state flag `isPresentingFacets`, which defines if the facet list is presented.

```swift Swift icon=code theme={"system"}
@State private var isPresentingFacets = false
```

Then declare a function that constructs the button which triggers the appearance of the facet list by toggling the `isPresentingFacets` flag.

```swift Swift icon=code theme={"system"}
private func facetsButton() -> some View {
  Button(action: {
    isPresentingFacets.toggle()
  },
  label: {
    Image(systemName: "line.horizontal.3.decrease.circle")
      .font(.title)
  })
}
```

Add the `FacetListObservableController` to the `ContentView` and a `facets` function constructing the facet list view.

```swift Swift icon=code theme={"system"}
@ObservedObject var facetListController: FacetListObservableController

@ViewBuilder
private func facets() -> some View {
  NavigationView {
    FacetList(facetListController) { facet, isSelected in
      VStack {
        FacetRow(facet: facet, isSelected: isSelected)
        Divider()
      }
    } noResults: {
      Text("No facet found")
        .frame(maxWidth: .infinity, maxHeight: .infinity)
    }
    .navigationBarTitle("Brand")
  }
}
```

The resulting `ContentView` code should look as follows:

```swift Swift icon=code theme={"system"}
  struct ContentView: View {

    @ObservedObject var searchBoxController: SearchBoxObservableController
    @ObservedObject var hitsController: HitsObservableController<StockItem>
    @ObservedObject var statsController: StatsTextObservableController
    @ObservedObject var facetListController: FacetListObservableController

    @State private var isEditing = false
    @State private var isPresentingFacets = false

    var body: some View {
      VStack(spacing: 7) {
        SearchBar(text: $searchBoxController.query,
                  isEditing: $isEditing,
                  onSubmit: searchBoxController.submit)
        Text(statsController.stats)
          .fontWeight(.medium)
        HitsList(hitsController) { (hit, _) in
          VStack(alignment: .leading, spacing: 10) {
            Text(hit?.name ?? "")
              .padding(.all, /*@START_MENU_TOKEN@*/10/*@END_MENU_TOKEN@*/)
            Divider()
          }
        } noResults: {
          Text("No Results")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
      }
      .navigationBarTitle("Algolia & SwiftUI")
      .navigationBarItems(trailing: facetsButton())
      .sheet(isPresented: $isPresentingFacets, content: facets)
    }

    @ViewBuilder
    private func facets() -> some View {
      NavigationView {
        FacetList(facetListController) { facet, isSelected in
          VStack {
            FacetRow(facet: facet, isSelected: isSelected)
            Divider()
          }
        } noResults: {
          Text("No facet found")
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        }
        .navigationBarTitle("Brand")
      }
    }

    private func facetsButton() -> some View {
      Button(action: {
        isPresentingFacets.toggle()
      },
      label: {
        Image(systemName: "line.horizontal.3.decrease.circle")
          .font(.title)
      })
    }

}
```

Complete the initializer of the `ContentView` with the `FacetListObservableController`.

```swift Swift icon=code theme={"system"}
struct ContentView_Previews: PreviewProvider {

  static let algoliaController = AlgoliaController()

  static var previews: some View {
    NavigationView {
      ContentView(searchBoxController: algoliaController.searchBoxController,
                  hitsController: algoliaController.hitsController,
                  statsController: algoliaController.statsController,
                  facetListController: algoliaController.facetListController)
    }.onAppear {
      algoliaController.searcher.search()
    }
  }

}
```

Update the live preview. Now you see a filter button on top right of your screen.
Click it to present the refinements list, select one or more refinements,
and then dismiss the refinements list by swiping it down to see the filtered result.

<Columns cols={2}>
  <img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/search-filter-button.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=7d036c46a14d6c692e13f3aee4052d95" alt="Screenshot of a mobile app interface showing a search box, a list of results, and a 'Search ' placeholder with a '10000 results (2ms)' label." style={{maxWidth:"300px"}} className="no-shadow" width="724" height="1420" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/search-filter-button.png" />

  <img src="https://mintcdn.com/algolia/BaxS3Doxn613Z9Q0/doc/guides/building-search-ui/getting-started/how-to/declarative/search-facet-list.png?fit=max&auto=format&n=BaxS3Doxn613Z9Q0&q=85&s=b24edb17bd5c72ac15b37c28b5f11933" alt="Screenshot of a mobile app screen showing a 'Brand' filter list with options like 'Sony (236)', 'Samsung (356)', and 'Insignia™ (230)', with 'Sony' selected." style={{maxWidth:"300px"}} className="no-shadow" width="724" height="1420" data-path="doc/guides/building-search-ui/getting-started/how-to/declarative/search-facet-list.png" />
</Columns>

## Going further

Your users can enter a query, and your app shows them results as they type. It also provides a possibility to filter the results even further using `RefinementList`. This is a great start, but you can go even further and improve on that.

* Have a look at more [complex examples of apps built with InstantSearch](/doc/guides/building-search-ui/resources/demos/ios).
* Head to the InstantSearch [components page](/doc/api-reference/widgets/ios) to see other components that you could use.
