Use <FloatVirtual> to create floating elements positioned relative to a non-DOM 'virtual' element.
Key implementation details:
- Initialization: Use the
@initial event to access show (visibility), reference (the virtual anchor), and floating (the floating element). - Defining the Anchor: Set
reference.value to an object containing a getBoundingClientRect() method. This method must return an object with width, height, x, y, top, left, right, and bottom properties. - Visibility: Toggle
show.value = true to display the element. - Portal: Use the
portal prop to render the element at the bottom of the <body> to avoid z-index conflicts. - Closing: Use the
useOutsideClick hook provided by @headlessui-float/vue to close the menu when clicking away.
<template>
<FloatVirtual portal @initial="onInitial">
<div class="bg-white shadow-md">context menu content</div>
</FloatVirtual>
</template>
<script setup>
import { computed, watchEffect } from 'vue'
import { FloatVirtual, useOutsideClick } from '@headlessui-float/vue'
function onInitial({ show, reference, floating }) {
function onContextMenu(e) {
e.preventDefault()
// Define the virtual element's position
reference.value = {
getBoundingClientRect() {
return {
width: 0, height: 0,
x: e.clientX, y: e.clientY,
top: e.clientY, left: e.clientX,
right: e.clientX, bottom: e.clientY,
}
},
}
show.value = true
}
watchEffect(onInvalidate => {
document.addEventListener('contextmenu', onContextMenu)
onInvalidate(() => document.removeEventListener('contextmenu', onContextMenu))
})
useOutsideClick(floating, () => {
show.value = false
}, computed(() => show.value))
}
</script>