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

# Hierarchical Menu

> Shows a hierarchical menu to navigate nested categories.

```kotlin Signature theme={"system"}
HierarchicalConnector(
    searcher: HitsSearcher,
    attribute: String,
    filterState: FilterState,
    hierarchicalAttributes: List<String>,
    separator: String
)
```

<Card title="Explore example code" icon="github" href="https://github.com/algolia/instantsearch-android/tree/master/examples/android">
  Browse the Hierarchical Menu example code on GitHub.
</Card>

## About this widget

A `Hierarchical Menu` is a component that displays a hierarchical navigation menu, based on facet attributes.

## Examples

```kotlin Kotlin icon=code theme={"system"}
class MyActivity : AppCompatActivity() {
    val searcher = HitsSearcher(
        applicationID = "YourApplicationID",
        apiKey = "YourSearchOnlyAPIKey",
        indexName = "YourIndexName"
    )
    val hierarchicalCategory = "categories"
    val hierarchicalCategoryLvl0 = "$categories.lvl0"
    val hierarchicalCategoryLvl1 = "$categories.lvl1"
    val hierarchicalCategoryLvl2 = "$categories.lvl2"
    val hierarchicalAttributes = listOf(
        hierarchicalCategoryLvl0,
        hierarchicalCategoryLvl1,
        hierarchicalCategoryLvl2
    )
    val filterState = FilterState()
    val separator = " > "
    val hierarchical = HierarchicalConnector(
        searcher = searcher,
        attribute = hierarchicalCategory,
        filterState = filterState,
        hierarchicalAttributes = hierarchicalAttributes,
        separator = separator
    )
    val connection = ConnectionHandler(hierarchical, searcher.connectFilterState(filterState))

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val view : HierarchicalView = HierarchicalAdapter() // your HierarchicalView implementation
        connection += hierarchical.connectView(view, HierarchicalPresenterImpl(separator))
        searcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        connection.disconnect()
        searcher.cancel()
    }
}
```

### Low-level API

If you want to fully control the Hierarchical Menu components and connect them manually,
use the following components:

* `Searcher`. The [`Searcher`](/doc/api-reference/widgets/instantsearch/android) that handles your searches.
* `FilterState`. The current state of the filters.
* `HierarchicalViewModel`. The logic applied to the hierarchical facets.
* `HierarchicalView`. The concrete hierarchical view.
* `HierarchicalPresenter`. The presenter that controls the sorting and other settings of the hierarchical menu.
* `HierarchicalItem`. A single node in the hierarchy.

```kotlin Kotlin icon=code theme={"system"}
class MyActivity : AppCompatActivity() {
    val searcher = HitsSearcher(
        applicationID = "YourApplicationID",
        apiKey = "YourSearchOnlyAPIKey",
        indexName = "YourIndexName"
    )
    val filterState = FilterState()

    val hierarchicalCategory = "categories"
    val hierarchicalCategoryLvl0 = "$categories.lvl0"
    val hierarchicalCategoryLvl1 = "$categories.lvl1"
    val hierarchicalCategoryLvl2 = "$categories.lvl2"
    val hierarchicalAttributes = listOf(
        hierarchicalCategoryLvl0,
        hierarchicalCategoryLvl1,
        hierarchicalCategoryLvl2
    )
    val separator = " > "
    val viewModel = HierarchicalViewModel(hierarchicalCategory, hierarchicalAttributes, separator)
    val connection = ConnectionHandler()

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val view: HierarchicalView = HierarchicalAdapter() // your `HierarchicalView` implementation

        connection += searcher.connectFilterState(filterState)
        connection += viewModel.connectFilterState(filterState)
        connection += viewModel.connectSearcher(searcher)
        connection += viewModel.connectView(view, HierarchicalPresenterImpl(separator))

        searcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        searcher.cancel()
        connection.disconnect()
    }
}
```

### Compose UI

InstantSearch provides `HierarchicalState` as a state model,
which implements the `HierarchicalView` interface.
You need to connect `HierarchicalState` to the `HierarchicalConnector` or `HierarchicalViewModel` like any other `HierarchicalView` implementation.

```kotlin Kotlin icon=code theme={"system"}
class MyActivity : AppCompatActivity() {
    val searcher = HitsSearcher(
        applicationID = "YourApplicationID",
        apiKey = "YourSearchOnlyAPIKey",
        indexName = "YourIndexName"
    )
    val hierarchicalCategory = "categories"
    val hierarchicalCategoryLvl0 = "$categories.lvl0"
    val hierarchicalCategoryLvl1 = "$categories.lvl1"
    val hierarchicalCategoryLvl2 = "$categories.lvl2"
    val hierarchicalAttributes = listOf(
        hierarchicalCategoryLvl0,
        hierarchicalCategoryLvl1,
        hierarchicalCategoryLvl2
    )
    val filterState = FilterState()
    val separator = " > "
    val hierarchicalState = HierarchicalState()
    val hierarchical = HierarchicalConnector(
        searcher = searcher,
        attribute = hierarchicalCategory,
        filterState = filterState,
        hierarchicalAttributes = hierarchicalAttributes,
        separator = separator
    )
    val connections = ConnectionHandler(hierarchical)

    init {
        connections += searcher.connectFilterState(filterState)
        connections += hierarchical.connectView(hierarchicalState, HierarchicalPresenterImpl(separator))
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            LazyColumn {
                items(hierarchicalState.hierarchicalItems) { item ->
                    HierarchicalItem( // your own UI composable to display `HierarchicalItem`
                        item = item,
                        onClick = { hierarchicalState.onSelectionChanged?.invoke(item.facet.value) }
                    )
                }
            }
        }
        searcher.searchAsync()
    }

    override fun onDestroy() {
        super.onDestroy()
        connections.disconnect()
        searcher.cancel()
    }
}
```

## Parameters

<ParamField body="searcher" type="HitsSearcher" required>
  The [`Searcher`](/doc/api-reference/widgets/instantsearch/android#hitssearcher) that handles your searches.
</ParamField>

<ParamField body="attribute" type="String" required>
  The attribute to filter.
</ParamField>

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

<ParamField body="hierarchicalAttributes" type="List<String>" required>
  The names of the hierarchical attributes that you need to target, in ascending order.
</ParamField>

<ParamField body="separator" type="String" required>
  The delimiter used to separate hierarchical facets.
  Usually something like " > ", including spaces as shown in this example.
</ParamField>

## View

<ParamField body="view" type="HierarchicalView" required>
  The view that renders the hierarchical menu.
</ParamField>

<ParamField body="presenter" type="HierarchicalPresenter" required>
  How to display the list of `HierarchicalItem`.
  Takes a list of `HierarchicalItem` and returns a new list of `HierarchicalItem`.
  A `HierarchicalItem` contains a `Facet`, its `level`, and a `displayName`.

  ```kotlin Kotlin icon=code theme={"system"}
  val view: HierarchicalView = HierarchicalAdapter()
  val separator = " > "
  val presenter = HierarchicalPresenterImpl(separator)
  hierarchical.connectView(view, presenter)

  // Example of `HierarchicalView` implementation
  class HierarchicalAdapter : HierarchicalView,
      ListAdapter<HierarchicalItem, HierarchicalViewHolder>(DiffUtilItem()) {
      override var onSelectionChanged: Callback<String>? = null

      override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HierarchicalViewHolder {
          return HierarchicalViewHolder(parent.inflate(R.layout.list_item_selectable, false))
      }

      override fun onBindViewHolder(holder: HierarchicalViewHolder, position: Int) {
          val item = getItem(position)
          holder.bind(item) { onSelectionChanged?.invoke(item.facet.value) }
      }

      override fun setTree(tree: List<HierarchicalItem>) {
          submitList(tree)
      }
  }

  class DiffUtilItem<T : Filter> : DiffUtil.ItemCallback<SelectableItem<T>>() {
      override fun areItemsTheSame(oldItem: SelectableItem<T>, newItem: SelectableItem<T>): Boolean {
          return oldItem.first == newItem.first
      }

      override fun areContentsTheSame(oldItem: SelectableItem<T>, newItem: SelectableItem<T>): Boolean {
          return oldItem == newItem
      }
  }
  ```
</ParamField>
