DEV Community

KarmaBlackshaw
KarmaBlackshaw

Posted on

Creating a dropdown menu using Vue3 and PopperJS

Been struggling for a while of creating a dropdown menu which auto adjusts when the element goes beyond the document's bounds.

Libraries used:

<script setup>
import { createPopper } from '@popperjs/core'

const popperInstance = ref(null)
const popcorn = ref(null)
const tooltip = ref(null)

onMounted(() => {
  useEventListener(popcorn.value, 'click', show)

  onClickOutside(popcorn.value, hide)

  popperInstance.value = createPopper(popcorn.value, tooltip.value, {
    placement: 'right-start',
    modifiers: [
      {
        name: 'offset',
        options: {
          offset: [0, 8]
        }
      }
    ]
  })
})

function show () {
  tooltip.value.setAttribute('data-show', '')
  popperInstance.value.update()
}

function hide () {
  tooltip.value.removeAttribute('data-show')
}

</script>

<template>
  <div>
    <div
      ref="tooltip"
      class="
        tooltip
        bg-neutral-900
        rounded
        p-2
        text-white
        text-xs
        w-[100px]
      "
    >
      <div
        class="arrow"
        data-popper-arrow
      ></div>

      <ul>
        <li
          v-for="i in 5"
          :key="i"
          class="
            px-2 py-2
            bg-neutral-900 hover:bg-neutral-800
            rounded
          "
        >
          Hey
        </li>
      </ul>
    </div>

    <button
      ref="popcorn"
      class="
        popcorn
        bg-blue-500
        text-white
        px-3 py-2
        rounded
      "
    >
      Add
    </button>
  </div>
</template>

<style lang="scss" scoped>
.tooltip {
  display: none;
}

.tooltip[data-show] {
  display: block;
}

.arrow,
.arrow::before {
  position: absolute;
  width: 8px;
  height: 8px;
  background: inherit;
}

.arrow {
  visibility: hidden;
}

.arrow::before {
  visibility: visible;
  content: '';
  transform: rotate(45deg);
}

.tooltip[data-popper-placement^='top'] > .arrow {
  bottom: -4px;
}

.tooltip[data-popper-placement^='bottom'] > .arrow {
  top: -4px;
}

.tooltip[data-popper-placement^='left'] > .arrow {
  right: -4px;
}

.tooltip[data-popper-placement^='right'] > .arrow {
  left: -4px;
}
</style>
Enter fullscreen mode Exit fullscreen mode

Top comments (0)