Skip to content

Dropdown

Dropdown menu component

GitHub Repo stars GitHub forks

Project Status

test codecov npm version license JavaScript Style Guide

Detailed changes for each release are documented in Changelog

If you are using vue 2.x version, please use v-dropdown 2.x version instead

Installation

Install the v-dropdown component into your project:

sh
npm i v-dropdown
sh
yarn add v-dropdown
sh
pnpm add v-dropdown

Basic Usage

template
<Dropdown @visible-change="change">
  <!-- trigger element -->
  <template #trigger>
    <!-- built-in trigger button -->
    <DropdownTrigger />
  </template>

  <!-- contents display in dropdown -->
  <DropdownContent>
    <div>
      some contents
    </div>
  </DropdownContent>
</Dropdown>
js
import { Dropdown, DropdownContent, DropdownTrigger } from 'v-dropdown'

function change(val) {
  console.log(val)
}

Examples

Quick Usage

The Dropdown component uses click trigger by default

template
<Dropdown>
  <template #trigger>
    <DropdownTrigger>Click me</DropdownTrigger>
  </template>
  <DropdownContent>
    <div>some contents</div>
  </DropdownContent>
</Dropdown>

Hover Activation

Open dropdown by hovering over trigger area

template
<Dropdown trigger="hover">
  <template #trigger>
    <DropdownTrigger>Hover me</DropdownTrigger>
  </template>
  ...
</Dropdown>

Context Menu Activation

Right-click trigger area to open dropdown

Mouse right click me
template
<Dropdown
  trigger="contextmenu"
  block
>
  <template #trigger>
    <div
      style="height: 10rem;"
      class="
        d-flex align-items-center justify-content-center
        bg-light rounded-3 px-3 py-1 fs-1 text-body-secondary w-100
      "
    >Mouse right click me</div>
  </template>
  ...
</Dropdown>

Toggle Cycle

Disable toggle cycle when clicking trigger

template
<Dropdown :toggle="false">
  ...
</Dropdown>

Disabled State

template
<Dropdown :disabled="true">
  ...
</Dropdown>

Manual Mode

Only opens dropdown when input value is "3"

template
<Dropdown
  :manual="true"
  ref="dropdown"
>
  <template #trigger>
    <input
      type="text"
      @input="inputChange"
    />
  </template>
  ...
</Dropdown>
js
import { ref } from 'vue'
const dropdown = ref(null)

function inputChange(e) {
  if (e.target.value === '3') {
    dropdown.value.display()
  } else {
    if (dropdown.value.visible) {
      dropdown.value.close()
    }
  }
}

Alignment Direction

Dropdown alignment relative to trigger

Align direction:
html
<Dropdown align="center">
  ...
</Dropdown>

Style Customization

Trigger rounded:
Content rounded:
template
<Dropdown>
  <template #trigger>
    <DropdownTrigger rounded="pill" />
  </template>
  <DropdownContent
    :border="false"
    rounded="medium"
  >
    <div>some contents</div>
  </DropdownContent>
</Dropdown>

Advanced styling via style or class

template
<Dropdown>
  <template #trigger>
    <DropdownTrigger class="border rounded-4 bg-primary-subtle p-2" />
  </template>
  <DropdownContent
    style="width: 500px;background-color:rgb(255, 174, 0);"
  >
    <div>some contents</div>
  </DropdownContent>
</Dropdown>

State & Utilities

Dropdown provides component state and utility functions to slots

template
<Dropdown>
  <template #trigger="{ visible, disabled, close }">
    <DropdownTrigger />
  </template>
  <template #default="{ visible, disabled, close }">
    <DropdownContent>
      <div>visible: {{ visible }}</div>
      <div>disabled: {{ disabled }}</div>
      <button
        class="btn btn-secondary"
        @click="close"
      >Close</button>
    </DropdownContent>
  </template>
</Dropdown>

The useDropdown composable provides state and utilities:

template
<Dropdown>
  <template #trigger>
    <DropdownTrigger />
  </template>
  <DropdownContent>
    <CustomContent />
  </DropdownContent>
</Dropdown>
vue
<template>
  <div>
    <div>visible: {{ visible }}</div>
    <div>disabled: {{ disabled }}</div>
    <button
      class="btn btn-secondary"
      @click="close"
    >Close</button>
  </div>
</template>
<script setup>
import { useDropdown } from 'v-dropdown'

const { visible, disabled, close } = useDropdown()
</script>

Slots

  • trigger Trigger element
  • default Dropdown content

Slot scope utilities:

ts
interface DropdownUtilities {
  visible: ComputedRef<boolean>
  disabled: ComputedRef<boolean>
  /** Close the dropdown */
  close: () => void
  /** Adjust content position */
  adjust: () => void
}

Usage example:

vue
<template>
  <Dropdown>
    <template #trigger="data: DropdownUtilities">
      <button type="button">visible: {{ data.visible }}</button>
    </template>

    <template #default="{ visible, disabled, close }: DropdownUtilities">
      <div>visible: {{ visible }}</div>
      <div>disabled: {{ disabled }}</div>
      <button
        class="btn btn-secondary"
        @click="close"
      >Close</button>
    </template>
  </Dropdown>
</template>
<script setup lang="ts">
import type { DropdownUtilities } from 'v-dropdown'
</script>

The adjust function is used to adjust the position of the drop-down bar content to align it with the trigger

INFO

In most cases, when the position and size of the trigger and the drop-down bar content change, the component will automatically adjust the position of the drop-down bar content. Therefore, it is only recommended to use it when the position of the drop-down bar does not meet expectations in scenarios with complex business interactions

Built-in button-style trigger component

  • default Trigger content (default: "Open")
  • append Opened state icon
  • default Dropdown content

Props

Dropdown component props

ts
interface DropdownProps {
  /**
   * Dropdown alignment
   * @default `left`
   */
  align?: 'left' | 'center' | 'right'
  /**
   * Toggle visibility on repeated trigger clicks
   * @default true
   */
  toggle?: boolean
  /**
   * Manual control mode
   * @default false
   */
  manual?: boolean
  /**
   * Disabled state
   * @default false
   */
  disabled?: boolean
  /**
   * Trigger displays in full-width mode
   * @default false
   */
  block?: boolean
  /**
   * Trigger method
   * @default `click`
   */
  trigger?: 'click' | 'hover' | 'contextmenu'
  /**
   * Spacing between trigger and dropdown
   * @default 5
   */
  gap?: number
  /**
   * Specify target container
   * @default `body`
   */
  appendTo: string | HTMLElement
}

DropdownContent component props

ts
interface ContentProps {
  /**
   * Show border
   * @default true
   */
  border?: boolean
  /**
   * Enable animations
   * @default true
   */
  animated?: boolean
  /**
   * Border radius
   * @default `small`
   */
  rounded?: 'small' | 'medium' | 'large'
  /**
   * z-index value
   * @default 3000
   */
  zIndex?: number
}

DropdownTrigger component props

ts
interface TriggerProps {
  /** Button border radius */
  rounded?: 'small' | 'medium' | 'large' | 'pill' | 'circle'
}

Events

visible-change

Triggered on visibility change

ts
`visible-change`: (visible: boolean) => void

open

Triggered when dropdown opens

ts
open: () => void

opened

Triggered after opening animation completes

ts
opened: () => void

close

Triggered when dropdown closes

ts
close: () => void

closed

Triggered after closing animation completes

ts
closed: () => void

API

Before using the plugin's API, declare a ref attribute for the component:

vue
<template>
  <Dropdown ref="dropdown" />
</template>

<script setup>
import { ref, onMounted } from 'vue'
import { Dropdown } from 'v-dropdown'

const dropdown = ref(null)
onMounted(() => {
  dropdown.value.display()
})
</script>

display

Open dropdown

ts
display: () => void

close

Close dropdown

ts
close: () => void

toggleVisible

Toggle dropdown state

ts
toggleVisible: () => void

Released under the MIT License.