Opening Healdess UI Dialog (Modal) via another Dialog (Modal) closes the previous Dialog (Modal) automatically?
Aravinda93 opened this issue · comments
I am using the HeadlessUI/Vue
component in my Nuxt 3
application to build the Dialog/Modals. I am using the latest version "@headlessui/vue": "^1.7.22"
and developing in Chrome latest browser.
Minimal reproduction repo in CodeSandBox
I am creating a DialogPanel1.vue
using the headlessui/vue
. I have a button in DialogPanel1.vue
on clicking it I am opening the DialogPanel2.vue
but within DialogPanel2.vue
when I click anywhere then it automatically closes the DialogPanel1.vue
which is behind the DialogPanel2.vue
.
Why is it closing DialogPanel1
automatically? I want to ensure that DialogPanel1
is closed only when I click the close button in DialogPanel1.vue
not for any click on DialogPanel2
. I tried adding the @click.stop
or @mousedown.stop
to prevent the propagation of the event but it's still not working. Can anyone please let me know the issue?
Following is my complete code /pages/Test.vue
:
<template>
<DialogPanel1 />
</template>
<script setup>
</script>
Following are my components /component/DialogPanel1.vue
:
<template>
<div class="mb-2">
<button
type="button"
@click="openModal1"
class="flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
>
<span class="pr-1"> Open Modal-1 </span>
</button>
</div>
<TransitionRoot appear :show="modal1" as="template">
<Dialog as="div" @close="closeModal" class="relative z-30">
<div class="fixed inset-0 overflow-y-auto">
<div
class="flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
class="dark:bg-slate-800 w-full transform overflow-auto rounded-2xl bg-white p-6 text-left align-middle shadow-xl transition-all z-20"
>
THIS IS MODAL-1
<button
class="flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
@click="openModal2"
>
MODAL-2
</button>
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>
<DialogPanel2 :modal2="modal2" @closeModal="hideModal2" />
</template>
<script setup>
import { TransitionRoot, Dialog, DialogPanel } from "@headlessui/vue";
const modal1 = ref(false);
const modal2 = ref(false);
//Function to open Modal-1
const openModal1 = () => {
console.log("Opening Modal-1");
modal1.value = true;
};
//Close the modal on click of the button
const closeModal = () => {
console.log("CLOSE MODAL-1");
modal1.value = false;
};
//Function to open Modal-2
const openModal2 = () => {
console.log("Open MODAL-2");
modal2.value = true;
};
const hideModal2 = () => {
console.log("Closing MODAL-2");
modal2.value = false;
};
</script>
Following is my /components/DialogPanel2.vue
:
<template>
<TransitionRoot appear :show="modal2" as="template">
<Dialog
as="div"
@close="closeModal"
class="relative z-50"
:initialFocus="completeButtonRef"
>
<div class="fixed inset-0 overflow-y-auto">
<div
class="flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
class="pt-5 w-full max-w-xl overflow-y-auto transform overflow-visible rounded-2xl bg-white dark:bg-slate-800 p-6 align-middle shadow-xl transition-all"
>
THIS IS MODAL-2
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>
</template>
<script setup>
import { TransitionRoot, Dialog, DialogPanel } from "@headlessui/vue";
const props = defineProps({
modal2: {
type: Boolean, //Show/hide the modal based on the flag
required: false,
},
});
const emits = defineEmits(["closeModal"]);
//Reference variables
const modal2 = ref(props.modal2);
watch(
() => props.modal2,
async (newValue) => {
modal2.value = newValue;
}
);
const closeModal = () => {
console.log("CLOSE MODAL-2");
modal2.value = false;
emits("closeModal");
};
const completeButtonRef = ref({}); // to avoid opening of the multiselect by default & initial focus
</script>
Why clicking anywhere on DialogPanel2.vue
automatically closes the previous Dialog DialogPanel1.vue
?
I got the same exact issue in headlessui/react v2+ now.
I solved it by placing the DialogPanel2.vue inside the DialogPanel1.vue:
<TransitionRoot appear :show="modal1" as="template" @close="closeModal">
<Dialog as="div" class="relative z-30">
<div class="fixed inset-0 overflow-y-auto">
<div
class="flex min-h-full items-center justify-center p-4 text-center"
>
<DialogPanel
class="dark:bg-slate-800 w-full transform overflow-auto rounded-2xl bg-gray-200 p-6 text-left align-middle shadow-xl transition-all z-20"
>
THIS IS MODAL-1
<button
class="flex secondary-button text-secondary dark:bg-transparent dark:hover:text-secondary dark:hover:bg-slate-700 mx-auto justify-center items-center rounded border focus:ring-0 focus:outline-none font-medium px-5 py-2.5 text-center min-w-[8rem] sm:min-w-[10rem] lg:min-w-[12rem]"
@click="openModal2"
>
MODAL-2
</button>
<DialogPanel2 :modal2="modal2" @closeModal="hideModal2" /><!-- move it here-->
</DialogPanel>
</div>
</div>
</Dialog>
</TransitionRoot>