Headlessui/vue Popover prevents the click on child element and unable to open the Select dropdown

39 Views Asked by At

I am using the Field from vee-validate which displays the select dropdown options. I want to add a PopoverPanel/Popover from @headlessui/vue to display some tooltip information on hovering over the Field so I have created a generic component which wraps the vee-validate Field.

After adding Popover I cannot select an option from vee-validate Field. I want the feature to get the tooltip menu when I hover over the vee-validate Select Field but when I click on the vee-validate Field I want to select any options just like any other Select dropdown.

I have created a sample project to reproduce the issue in CodeSandBox.

Following is the code I have in my Nuxt 3 application:

components/GenericTooltip.vue:

<template>
  <Popover v-slot="{ open, close }">
    <PopoverButton
      class="focus:outline-none mr-2"
      @mouseover="hoverPopover($event, open)"
      @mouseleave="closePopover($event, close)"
    >
      <slot />
    </PopoverButton>

    <PopoverPanel
      class="mt-3 absolute z-50 dark:bg-gray-700 bg-gray-300 dark:text-white text-black rounded-lg p-2 inline-block after:absolute after:border-4 dark:after:border-gray-700 after:border-gray-300 after:-left-0 after:top-1/3 after:-translate-x-1/2 after:rotate-45 transform -translate-y-[30%]"
    >
      {{ tooltipInfo }}
    </PopoverPanel>
  </Popover>
</template>
  
   
<script setup>
import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue";
const popoverHover = ref(false);
const popoverTimeout = ref();
const tooltipInfo = ref("");

//On hover show the tooltip with information
const hoverPopover = (e, open) => {
  console.log("1. Hover Pop Over");
  console.log(e);
  popoverHover.value = true;
  if (!open) {
    e.target.parentNode.click();
  }

  //Add tooltip information
  tooltipInfo.value = "This is the ToolTip Sample Value";
};

//On mouse leave close it
const closePopover = (e, close) => {
  console.log("3. Hover CLose Pop Over");
  popoverHover.value = false;
  if (popoverTimeout.value) clearTimeout(popoverTimeout.value);
  popoverTimeout.value = setTimeout(() => {
    if (!popoverHover.value) {
      close();
    }
  }, 100);
};
</script>

Following is its usage and wrapping the vee-validate Field component:

components/HoverMenuTest.vue:

<template>
  <div class="flex flex-col items-center w-full">
    <GenericTooltip>
      <div
        class="relative w-full h-full bg-gray-50 dark:text-white dark:bg-gray-700 dark:border-gray-600 border-gray-300 border rounded text-center block overflow-hidden"
      >
        <Field
          as="select"
          :name="name"
          v-model="item"
          class="w-full h-full bg-transparent p-2 outline-none dark:bg-gray-700"
        >
          <option
            v-for="option in options"
            :value="option.value"
            :key="option.value"
            :selected="option.selected"
          >
            {{ option.text }}
          </option>
        </Field>

        <Icon
          icon="iconamoon:arrow-down-2-bold"
          class="absolute right-2 top-1/2 transform -translate-y-1/2"
        />
      </div>

      <div class="text-center">
        <ErrorMessage :name="name" class="text-red-500 mt-2 italic" />
      </div>
    </GenericTooltip>
  </div>
</template>
  
<script setup>
import { Icon } from "@iconify/vue";
import { Field, ErrorMessage } from "vee-validate";

const props = defineProps({
  options: {
    type: Array,
    required: false,
  },
  name: {
    type: String,
    required: false,
  },
});

const item = ref(props.options[0].value);
</script>
  
<style>
select {
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none;
  background-image: none;
}
</style>

Following is their usage in pages/Test.vue:

<template>
  <HoverMenuTest v-model="type" :name="'type'" :options="options" />
</template>

<script setup>
const type = useState("type", () => ({}));
const options = [
  { value: "value1", text: "Option 1", selected: true },
  { value: "value2", text: "Option 2" },
  { value: "value3", text: "Option 3" },
];
</script>

The following GIF shows that when I hover over the Field I can get the tooltip information as I want but when clicking on the Field I cannot get any dropdown options.

enter image description here

If I remove the <GenericTooltip> wrapping in HoverMenuTest.vue for the vee-validate Field, it works fine and can select the required options. I want this GenericToolTip.vue component as I plan to reuse it in multiple places rather than copying the code.

I tried adding the @click.stop to my PopoverButton:

 <PopoverButton
      class="focus:outline-none mr-2"
      @mouseover="hoverPopover($event, open)"
      @mouseleave="closePopover($event, close)"
      @click.stop="handleClick($event, open, close)"
    >
      <slot />
    </PopoverButton>

// Handle click event to prevent Popover from capturing it when Field is clicked
const handleClick = (e, open, close) => {
  console.log(e.target.tagName);
  if (e.target.tagName === "SELECT") {
    // If the Field is clicked, prevent the Popover from capturing the click event
    e.stopPropagation();
    e.preventDefault();
  } else {
    // Otherwise, handle the click event as usual
    hoverPopover(e, open);
  }
};

But this is also not working and I am still unable to see dropdown options.

0

There are 0 best solutions below