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

# ais-menu-select

> Lets users refine search results using a drop-down menu.

<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">Vue</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="false"><a className="afs-option" href="/doc/api-reference/widgets/menu-select/js"><span className="afs-option-name">JavaScript</span><span className="afs-option-lib">InstantSearch.js</span></a></li>
      <li role="option" aria-selected="false"><a className="afs-option" href="/doc/api-reference/widgets/menu-select/react"><span className="afs-option-name">React</span><span className="afs-option-lib">React InstantSearch</span></a></li>
      <li role="option" aria-selected="true"><a className="afs-option is-current" href="/doc/api-reference/widgets/menu-select/vue"><span className="afs-option-name">Vue</span><span className="afs-option-lib">Vue InstantSearch</span></a></li>
    </ul>
  </div>
</div>

```vue Signature theme={"system"}
<ais-menu-select
  attribute="string"
  // Optional parameters
  :limit="number"
  :sort-by="string[] | function"
  :transform-items="function"
  :class-names="object"
/>
```

## Import

<Tabs>
  <Tab title="Component">
    To ensure optimal bundle sizes,
    see [Optimize build size](/doc/guides/building-search-ui/going-further/improve-performance/vue#optimize-build-size).

    ```js Vue icon=code theme={"system"}
    import { AisMenuSelect } from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    export default {
      components: {
        AisMenuSelect
      },
      // ...
    };
    ```
  </Tab>

  <Tab title="Plugin">
    This imports all widgets, even the ones you don't use.
    For more information, see [Get started with Vue InstantSearch](/doc/guides/building-search-ui/getting-started/vue).

    ```js JavaScript icon="code" theme={"system"}
    import Vue from "vue";
    import InstantSearch from "vue-instantsearch";
    // Use "vue-instantsearch/vue3/es" for Vue 3

    Vue.use(InstantSearch);
    ```
  </Tab>
</Tabs>

<Card title="See this widget in action" icon="monitor-play" href="https://instantsearchjs.netlify.app/stories/vue/?selectedKind=ais-menu-select" horizontal>
  Preview this widget and its behavior.
</Card>

## About this widget

The `ais-menu-select` widget allows a user to select a single value to refine inside a [`select`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select) element.

### Requirements

The [`attribute`](#param-attribute) provided to the widget must be in attributes for faceting,
either on the [dashboard](/doc/guides/managing-results/refine-results/faceting/how-to/declaring-attributes-for-faceting-with-dashboard) or using the [`attributesForFaceting`](/doc/api-reference/api-parameters/attributesForFaceting) parameter with the API.

## Examples

```vue Vue icon=code theme={"system"}
<ais-menu-select attribute="categories" />
```

## Props

<ParamField body="attribute" type="string" required>
  The name of the attribute in the record.

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select attribute="categories" />
  ```
</ParamField>

<ParamField body="limit" type="number" default={10}>
  The maximum number of values to display.

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select
    [...]
    :limit="20"
  />
  ```
</ParamField>

<ParamField body="sort-by" type="string[] | function" default="Uses facetOrdering if set, ['name:asc', 'count:desc']">
  How to sort refinements. Must be one or more of the following strings:

  * `"count:asc"`
  * `"count:desc"`
  * `"name:asc"`
  * `"name:desc"`
  * `"isRefined"`

  It's also possible to give a function,
  which receives items two by two,
  like JavaScript's [`Array.sort`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort).

  If `facetOrdering` is set for this facet in `renderingContent`,
  and no value for `sortBy` is passed to this widget,
  `facetOrdering` is used, and the default order as a fallback.

  <Note>
    To [prevent creating infinite loops](https://support.algolia.com/hc/en-us/articles/4406511683217-Vue-InstantSearch-How-do-I-prevent-infinite-loops),
    avoid passing arrays, objects, or functions directly in the template.
    These values aren't referentially equal on each render,
    which causes the widget to re-register every time.
    Instead, define them in your component's `data` option and reference them in the template.
  </Note>

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select :sort-by="['isRefined', 'count:desc']" />
  ```
</ParamField>

<ParamField body="transform-items" type="function" default="items => items">
  A function that receives the list of items before they are displayed.
  It should return a new array with the same structure.
  Use this to transform, filter, or reorder the items.

  The function also has access to the full `results` data,
  including all standard [response parameters](/doc/guides/building-search-ui/going-further/backend-search/in-depth/understanding-the-api-response/)
  and [parameters from the helper](https://community.algolia.com/algoliasearch-helper-js/reference.html#query-parameters),
  such as `disjunctiveFacetsRefinements`.

  ```vue Vue icon=code theme={"system"}
  <template>
    <!-- ... -->
    <ais-menu-select :transform-items="transformItems" />
  </template>

  <script>
  export default {
    methods: {
      transformItems(items) {
        return items.map((item) => ({
          ...item,
          label: item.label.toUpperCase(),
        }));
      },
    },
  };
  </script>
  ```
</ParamField>

<ParamField body="class-names" type="object" default="{}">
  The [CSS classes you can override](/doc/guides/building-search-ui/widgets/customize-an-existing-widget/vue#style-your-widgets):

  * `.ais-MenuSelect`. The root element of the widget
  * `.ais-MenuSelect--noRefinement`. The root element of the widget with no refinement
  * `.ais-MenuSelect-select`. The`select` element
  * `.ais-MenuSelect-option`. The `option` elements of the `select`

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select
    [...]
    :class-names="{
      'ais-MenuSelect': 'MyCustomMenuSelect',
      'ais-MenuSelect-option': 'MyCustomMenuSelectOption',
      // ...
    }"
  />
  ```
</ParamField>

## Customize the UI

<ParamField body="default">
  The slot to override the complete DOM output of the widget.

  When you implement this slot,
  none of the other slots will change the output,
  as the default slot surrounds them.

  **Scope**

  * `items: object[]`. The values applicable to this menu.
  * `canRefine: boolean`. Can the refinement be applied?
  * `refine: (value: string) => void`. A function to select a refinement.
  * `createURL: (item: string) => string`. A function to return a link for this refinement.
  * `sendEvent: (eventType: 'click', facetValue: string) => void`. The function to send `click` events.

    * The `view` event is automatically sent when the facets are rendered.
    * The `click` event is automatically sent when `refine` is called.

    To learn more, see the [`insights`](/doc/api-reference/widgets/insights/vue) middleware.

  Where each item is an `object` containing:

  * `value: string`. The value of the menu item.
  * `label: string`. Human-readable value of the menu item.
  * `count: number`. Number of results matched after a refinement is applied.
  * `isRefined: boolean`. Indicates if the refinement is applied.

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select attribute="categories">
    <template v-slot="{ items, canRefine, refine, sendEvent }">
      <select
        :disabled="!canRefine"
        @change="refine($event.currentTarget.value)"
      >
        <option value="">All</option>
        <option
          v-for="item in items"
          :key="item.value"
          :value="item.value"
          :selected="item.isRefined"
        >
          {{ item.label }}
        </option>
      </select>
    </template>
  </ais-menu-select>
  ```
</ParamField>

<ParamField body="item">
  The slot to override the content of an `option` element.
  Make sure to use `template` as the root,
  since any other elements inside an `option` are not allowed.

  **Scope**

  * `item: object`. The values applicable to the `option`.

  Where item is an `object` containing:

  * `value: string`. The value of the menu item.
  * `label: string`. Human-readable value of the menu item.
  * `count: number`. Number of results matched after a refinement is applied.
  * `isRefined: boolean`. Indicates if the refinement is applied.

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select attribute="categories">
    <template v-slot:item="{ item }">
      {{ item.label }}
    </template>
  </ais-menu-select>
  ```
</ParamField>

<ParamField body="defaultOption">
  The slot to override the content of the `option` element which selects "all items".
  Make sure to use `template` as the root, since any other elements inside an `option` are not allowed.

  **Scope**

  No scope is provided to this slot.

  ```vue Vue icon=code theme={"system"}
  <ais-menu-select attribute="categories">
    <template v-slot:defaultOption>See all categories</template>
  </ais-menu-select>
  ```
</ParamField>

## HTML output

```html HTML icon=code-xml theme={"system"}
<div class="ais-MenuSelect">
  <select class="ais-MenuSelect-select">
    <option class="ais-Menu-option">Apple (50)</option>
    <!-- more items -->
  </select>
</div>
```

<Note>
  If SEO is important for your search page, ensure that your custom HTML is optimized for search engines:

  * Use `<a>` tags with `href` attributes to allow search engine bots to follow links.
  * Use semantic HTML and include [structured data](https://developers.google.com/search/docs/appearance/structured-data) when relevant.

  For more guidance, see the [SEO checklist](/doc/guides/building-search-ui/resources/seo/js).
</Note>
