Dropdown

v-modelundefined
Boolean
Set it to true/false to programatically show or hide dropdown content. Model is optional

auto-close-menufalse
Boolean
If true clicking any dropdown menu item automatically closes dropdown

auto-placementfalse
Boolean
Automatically calculates best placement for floating element

base"dropdown"
String
Base name used to style component

fliptrue
Boolean
Allows fliping dropdown to opposite placement if outside of current view

mod-headerempty string
String
Style of the menu header

mod-itemempty string
String
Style of the menu item

nameempty string
String
Name of the component

offset-x0
Number
Offset of dropdown relative to reference element. See how to use this offset here

offset-y0
Number
Offset of dropdown relative to reference element. See how to use this offset here

placement"bottom-start"
String
Initial placement of dropdown content. See valid values in FloatingUI documentation

transition"fade-scale"
String
Sets animation effect when showing or hiding dropdown. Valid values are: 'fade', 'fade-slide', 'fade-scale' or empty string to disable animations. CSS variables: --dropdown-transition-duration, --dropdown-transition-slide, --dropdown-transition-scale

trigger"click"
String
How to trigger dropdown. Valid triggers are 'click', 'focus' and 'hover'

variantempty string
String
Active variant of the element mod-* props
state:opened
Emitted after dropdown is opened

state:closed
Emitted after dropdown is closed

update:modelValue
Emitted after model change
reference
Slot for element that activates dropdown. Dropdown is positioned relative to element that has ref set to reference. Slot props: reference, onTrigger and isOpen

default
Slot for dropdown content. Slot props: hide()

v-dropdown-menu-item

showContextDropdown($event, contextData: Object)
Shows context menu. Context data is available in slot props of default slot. Only available on v-dropdown-context

To control dropdown visibility and placement you can use:

  • element in the reference slot of the v-dropdown (recommended method)
  • element in the v-trigger component. See the usage and example.

To control it programatically you can add optional v-model or call exposed show() and hide() functions.

Teleport

Open dropdown is by default appended to the body element.

Context menus

You can set up context menus with the v-dropdown-context component that does not require activating element. See the example below.


Example - simple dropdown

    <template>
  <v-dropdown
    auto-close-menu
    :offsetY="5"
  >
    <template #reference="{ reference, onTrigger }">
      <v-button-chevron
        :ref="reference"
        :chevron="{ class: 'ml-2' }"
        v-on="onTrigger"
      >
        Dropdown menu
      </v-button-chevron>
    </template>

    <v-card
      width="320px"
    >
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Second menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item
        active
        tag="button"
      >
        Active menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Third menu item
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown>
</template>
  

Example - props

bottom-start
click
false
false
fade-scale
    <template>
  <v-dropdown
    v-bind="example"
    @state:opened="events.unshift({ ev: 'state:opened', data: $event })"
    @state:closed="events.unshift({ ev: 'state:closed', data: $event })"
  >
    <template #reference="{ reference, onTrigger, isOpen }">
      <v-button-chevron
        :ref="reference"
        :chevron="{ class: 'ml-2' }"
        v-on="onTrigger"
        :switch="isOpen"
      >
        Dropdown menu
      </v-button-chevron>
    </template>

    <v-card width="320px">
      <v-dropdown-menu-item tag="button">Menu item</v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">Second menu item</v-dropdown-menu-item>
      <v-dropdown-header>Menu header</v-dropdown-header>
      <v-dropdown-menu-item
        active
        tag="button"
      >
        Active menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Another menu item
      </v-dropdown-menu-item>
      <v-divider />
      <v-dropdown-menu-item
        disabled
        tag="button"
      >
        Disabled menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">Menu item</v-dropdown-menu-item>
    </v-card>
  </v-dropdown>

</template>
  
    <script setup>
import { ref, reactive } from "vue";

let example = reactive({
  placement: "bottom-start",
  offsetX: 0,
  offsetY: 5,
  flip: false,
  autoCloseMenu: false,
  transition: "fade-scale",
  trigger: "click",
});

let events = ref([]);
</script>
  

Example - alternative styles

Dropdown comes with some default alternative styles.

    <template>
  <!-- relaxed -->

  <v-dropdown
    base="relaxedDropdown"
    :offsetY="5"
  >
    <template #reference="{ reference, onTrigger }">
      <v-button-chevron
        :ref="reference"
        :chevron="{ class: 'ml-2' }"
        class="mr-4"
        v-on="onTrigger"
      >
        Dropdown menu (relaxed)
      </v-button-chevron>
    </template>

    <v-card
      width="320px"
      class="flex flex-col items-center py-3"
    >
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Second menu item
      </v-dropdown-menu-item>
      <v-dropdown-header>
        Menu header
      </v-dropdown-header>
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Another menu item
      </v-dropdown-menu-item>
      <v-divider class="w-11/12 mx-auto" />
      <v-dropdown-menu-item
        disabled
        tag="button"
      >
        Disabled menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown>

  <!-- flat -->

  <v-dropdown
    :offsetY="5"
  >
    <template #reference="{ reference, onTrigger }">
      <v-button-chevron
        :ref="reference"
        mod-button="shape:square"
        :chevron="{ class: 'ml-2' }"
        v-on="onTrigger"
        class="mt-4 md:mt-0"
      >
        Dropdown menu (flat)
      </v-button-chevron>
    </template>
    <v-card
      width="320px"
      mod-card="preset:flatDropdown"
    >
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Second menu item
      </v-dropdown-menu-item>
      <v-dropdown-header>
        Menu header
      </v-dropdown-header>
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Another menu item
      </v-dropdown-menu-item>
      <v-divider class="w-11/12 mx-auto" />
      <v-dropdown-menu-item
        disabled
        tag="button"
      >
        Disabled menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown>
</template>
  

Example - custom content

Dropdowns are not limited to simple dropdown menus. See the below example for more advanced dropdown that uses input to filter menu items.

    <template>
  <v-dropdown :offsetY="5">
    <template #reference="{ reference, onTrigger }">
      <v-button-chevron
        :ref="reference"
        :chevron="{ class: 'ml-2' }"
        v-on="onTrigger"
      >
        Filterable menu
      </v-button-chevron>
    </template>

    <v-card width="280px">
      <div class="px-4 py-1">
        <v-input
          v-model="filter"
          placeholder="Filter"
          base="underlinedInput"
          :close-button="{
            modCloseButton: 'size:small',
          }"
          clearable
        ></v-input>
      </div>
      <v-dropdown-menu-item
        v-for="item in menuItems"
        :key="item"
        tag="button"
      >
        {{ item }}
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown>
</template>
  
    <script setup>
import { ref, computed } from "vue";
import { languages } from "../example-data/data.js";

let filter = ref("");

let menuItems = computed(() => {
  return languages.filter((i) => {
    return i.toLowerCase().indexOf(filter.value.toLowerCase()) !== -1;
  });
});
</script>
  

Example - open by id

You can also control state of the dropdown menu by using v-trigger component. The for prop of the v-trigger should be the same as id of the dropdown. The advantage of this method is that v-triggers can be put anywhere in application. Read more about v-trigger here.

    <template>
  <v-dropdown id="dropdown" :offsetY="5">
    <v-card width="320px">
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Second menu item
      </v-dropdown-menu-item>
      <v-dropdown-header>
        Menu header
      </v-dropdown-header>
      <v-dropdown-menu-item tag="button">
        Active menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Another menu item
      </v-dropdown-menu-item>
      <v-divider />
      <v-dropdown-menu-item disabled tag="button">
        Disabled menu item
      </v-dropdown-menu-item>
      <v-dropdown-menu-item tag="button">
        Menu item
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown>

  <v-trigger for="dropdown" v-slot="{ reference, onTrigger, isOpen }">
    <v-button :ref="reference" v-on="onTrigger">
      Dropdown menu
      <v-chevron rotate180 :switch="isOpen" class="ml-2"></v-chevron>
    </v-button>
  </v-trigger>
</template>
  

Example - context dropdown

To make context menu use v-dropdown-context. This component exposes showContextDropdown($event, { contextData }) function that controls visibility state of the menu and sets context data. The first argument, mouse event, allows computing position of the menu. The second argument defines data that is provided in the default slot of the dropdown component.

english
swedish
korean
german
icelandic
japanese
Language:
    <template>
  <div class="mb-4 flex">
    <div
      v-for="(language, index) in languages"
      :key="language"
      class="mr-4 cursor-pointer border p-2 hover:bg-secondary-50 dark:border-dark-700 dark:hover:bg-dark-700"
      @contextmenu.prevent="
        contextMenu.showContextDropdown($event, { language, index })
      "
    >
      {{ language }}
    </div>
  </div>

  Language: {{ currentLanguage }}

  <v-dropdown-context
    ref="contextMenu"
    auto-close-menu
    v-slot="{ language, index }"
  >
    <v-card width="280px">
      <v-dropdown-menu-item @click="currentLanguage = language">
        Switch to {{ language }}
      </v-dropdown-menu-item>
      <v-dropdown-menu-item @click="search(language)">
        Search {{ language }}
      </v-dropdown-menu-item>
      <v-divider />
      <v-dropdown-menu-item @click="languages.splice(index, 1)">
        Remove {{ language }}
      </v-dropdown-menu-item>
      <v-divider />
      <v-dropdown-menu-item @click="languages.push('spanish')">
        Add spanish
      </v-dropdown-menu-item>
      <v-dropdown-menu-item @click="languages.push('french')">
        Add french
      </v-dropdown-menu-item>
    </v-card>
  </v-dropdown-context>
</template>
  
    <script setup>
import { ref } from "vue";

let contextMenu = ref(null);

let currentLanguage = ref("");

let languages = ref([
  "english",
  "swedish",
  "korean",
  "german",
  "icelandic",
  "japanese",
]);

let search = (data) => window.open("https://google.com/search?q=" + data);
</script>