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

# Dynamic Facet List

> Shows ordered facets and facet values based on index settings and rules.

```swift Signature theme={"system"}
DynamicFacetListConnector(
  searcher: Searcher,
  filterState: FilterState,
  orderedFacets: [AttributedFacets],
  selections: [Attribute: Set<String>],
  selectionModeForAttribute: [Attribute: SelectionMode],
  filterGroupForAttribute: [Attribute: FilterGroupDescriptor],
  controller: DynamicFacetListController
)
```

<Card title="Explore example code" icon="github" href="https://github.com/algolia/instantsearch-ios/tree/master/Examples/Showcase">
  Browse the Dynamic Facet List example code on GitHub.
</Card>

## About this widget

`DynamicFacetList` is a view that displays the ordered list of facets and facet values.
The order of groups and facet values in each group is defined by the corresponding index settings and applied index rules.
You can configure the facet merchandising through the corresponding index setting.
To learn more, see [Facet display](/doc/guides/building-search-ui/ui-and-ux-patterns/facet-display/ios).

### Requirements

You must set the attributes for faceting and configure the facet order, either using the [dashboard](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting-with-dashboard) or with the API parameters [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting) and [`renderingContent`](/doc/api-reference/api-parameters/renderingContent).

You must also set the [`facets`](/doc/api-reference/api-parameters/facets) property of the query with `Searcher.request.query.facets` and provide the facet attributes you want to retrieve.

<Note>
  You must use InstantSearch iOS v7.12.0 or later to use Dynamic Facet List.
</Note>

## Examples

Instantiate a `DynamicFacetListConnector`, set the query facets and launch an initial search on its searcher.

```swift Swift icon=code theme={"system"}
let searcher = HitsSeacher(appID: "YourApplicationID",
                           apiKey: "YourSearchOnlyAPIKey",
                           indexName: "YourIndexName")
searcher.request.query.facets = ["brand", "color", "size", "country"]

let filterState = FilterState()
let dynamicFacetListController = DynamicFacetListTableViewController()

let dynamicFacetlistConnector = DynamicFacetListConnector(searcher: searcher,
                                                          filterState: filterState,
                                                          selectionModeForAttribute: [
                                                            "color": .multiple,
                                                            "country": .multiple
                                                          ],
                                                          filterGroupForAttribute: [
                                                            "brand": ("brand", .or),
                                                            "color" : ("color", .or),
                                                          ],
                                                          controller: dynamicFacetListController)

searcher.connectFilterState(filterState)
searcher.search()
```

## Parameters

<ResponseField name="searcher" type="Searcher" required>
  The [`Searcher`](/doc/api-reference/widgets/instantsearch/ios) that handles your searches.
</ResponseField>

<ResponseField name="filterState" type="FilterState" required>
  The [`FilterState`](/doc/api-reference/widgets/filter-state/ios) that holds your filters.
</ResponseField>

<ResponseField name="orderedFacets" type="[AttributedFacets]" post={["default: []"]}>
  The ordered list of attributed facets.
</ResponseField>

<ResponseField name="selections" type="[Attribute: Set<String>]" post={["default: []"]}>
  The mapping between a facet attribute and a set of selected facet values.
</ResponseField>

<ResponseField name="selectionModeForAttribute" type="[Attribute: SelectionMode]" post={["default: [:]"]}>
  The mapping between a facet attribute and a facet values selection mode. If not provided, the default selection mode is `.single`.
</ResponseField>

<ResponseField name="filterGroupForAttribute" type="[Attribute: FilterGroupDescriptor]" post={["default: [:]"]}>
  The mapping between a facet attribute and a descriptor of a filter group where the corresponding facet filters are stored in the filter state.
</ResponseField>

<ResponseField name="controller" type="DynamicFacetListController">
  `DynamicFacetListController` implementation to connect.
</ResponseField>

## Low-level API

If you want to fully control the `DynamicFacetList` components and connect them manually, you can use the following components:

* `Searcher`: the [`Searcher`](/doc/api-reference/widgets/instantsearch/ios) that handles your searches.
* `FilterState`: the current state of the filters.
* `DynamicFacetListInteractor`: dynamic facet list business logic
* `DynamicFacetListController`: controller presenting the ordered list of facets and handling the user interaction

```swift Swift icon=code theme={"system"}
let searcher = HitsSearcher(appID: "YourApplicationID",
                            apiKey: "YourSearchOnlyAPIKey",
                            indexName: "YourIndexName")
searcher.request.query.facets = ["brand", "color", "size", "country"]

let filterState = FilterState()
let dynamicFacetListController = DynamicFacetListTableViewController()

let dynamicFacetListInteractor = DynamicFacetListInteractor(selectionModeForAttribute: [
                                                              "color": .multiple,
                                                              "country": .multiple
                                                            ])

dynamicFacetListInteractor.connectSearcher(searcher)
dynamicFacetListInteractor.connectFilterState(filterState, filterGroupForAttribute: [
                                                             "brand": ("brand", .or),
                                                             "color" : ("color", .or),
                                                           ])
dynamicFacetListInteractor.connectController(dynamicFacetListController)

searcher.connectFilterState(filterState)
searcher.search()
```

## Customizing your view

### UIKit

InstantSearch iOS provides the `DynamicFacetListTableViewController`, which is the `UITableViewController` subclass that implements the `DynamicFacetListController` protocol.
If you want to use another component, such as a `UICollectionView` or a third-party view, or if you want to introduce some custom behavior to the already provided UIKit component, you can create your own controller conforming to the `DynamicFacetListController` protocol.

#### Protocol

`func setOrderedFacets(_ orderedFacets: [AttributedFacets])`
Update the list of the ordered attributed facets

`func setSelections(_ selections: [Attribute: Set<String>])`
Update the facet selections

`var didSelect: ((Attribute, Facet) -> Void)?`
Closure to trigger when user selects a facet

### SwiftUI

InstantSearch iOS provides the `DynamicFacetListObservableController`, an implementation of the `DynamicFacetListController` protocol adapted for usage with SwiftUI.
It provides `orderedFacets` and `selections` properties with convenient `toggle` and `isSelected` functions which let you implement your own SwiftUI view.

#### Implementation example

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

  @ObservedObject var dynamicFacetListController: DynamicFacetListObservableController

  var body: some View {
    ScrollView {
      ForEach(dynamicFacetListController.orderedFacets, id: \.attribute) { orderedFacet in
        VStack(spacing: 0) {
          // Facet header
          ZStack {
            Color(.systemGray5)
            Text(orderedFacet.attribute.rawValue)
              .fontWeight(.semibold)
              .frame(maxWidth: .infinity, alignment: .leading)
              .padding(.horizontal, 5)
          }
          // Facet values
          ForEach(orderedFacet.facets, id: \.value) { facet in
            VStack(spacing: 0) {
              FacetRow(facet: facet,
                      isSelected: dynamicFacetListController.isSelected(facet, for: orderedFacet.attribute))
                .onTapGesture {
                  dynamicFacetListController.toggle(facet, for: orderedFacet.attribute)
                }
                .frame(minHeight: 44, idealHeight: 44, maxHeight: .infinity, alignment: .center)
                .padding(.horizontal, 5)
            }
          }
        }
      }
    }
  }
}
```
