0

I am creating a reusable Dialog modal in my application and it works fine when I use it once in my page but when I use more than once then I get the error: There are no focusable elements inside the <FocusTrap />.

Following is my reusable Dialog component from HeadlessUI in my Vue3/Nuxt 3 application: ExtensionModal.vue:

<template>
  <div class="flex-col items-center">
    <div class="mb-2">
      <button
        type="button"
        @click="openModal"
        class="block rounded-full text-blue-700 hover:text-white border border-blue-700 hover:bg-blue-800 focus:ring-0 focus:outline-none focus:ring-blue-300 font-medium text-sm px-5 py-2.5 text-center mr-2 mb-2 dark:border-blue-500 dark:text-blue-500 dark:hover:text-white dark:hover:bg-blue-600 dark:focus:ring-blue-800"
      >
        {{ buttonLabel }}
      </button>
    </div>
  </div>

  <TransitionRoot appear :show="showExtensionModal" as="template">
    <Dialog as="div" @close="closeModal" class="relative z-10">
      <TransitionChild
        as="template"
        enter="duration-300 ease-out"
        enter-from="opacity-0"
        enter-to="opacity-100"
        leave="duration-200 ease-in"
        leave-from="opacity-100"
        leave-to="opacity-0"
      >
        <div class="fixed inset-0 bg-black bg-opacity-25" />
      </TransitionChild>
      <div
        class="fixed h-fit inset-0 overflow-y-auto flex items-center justify-center"
      >
        <div
          class="fixed inset-0 overflow-y-auto flex items-center justify-center"
        >
          <TransitionChild
            as="template"
            enter="duration-300 ease-out"
            enter-from="opacity-0 scale-95"
            enter-to="opacity-100 scale-100"
            leave="duration-200 ease-in"
            leave-from="opacity-100 scale-100"
            leave-to="opacity-0 scale-95"
          >
            <DialogPanel
              class="flex-grow w-full h-fit transform overflow-visible rounded-2xl bg-gray-200 dark:bg-slate-800 p-6 text-left align-middle shadow-xl transition-all max-w-[90vw] sm:max-w-[80vw] md:max-w-[70vw] lg:max-w-[60vw] xl:max-w-[50vw] 2xl:max-w-[40vw]"
            >
              <DialogTitle
                as="h3"
                class="flex text-lg font-medium leading-6 text-gray-900 justify-center dark:text-white"
              >
                {{ buttonTitle }}
              </DialogTitle>

              <form @submit="onSubmit($event)">
                  <div class="flex mt-5">
                    <div class="w-full z-40">
                      <select
                        v-model="element"
                        class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500"
                      >
                        <option
                          v-for="option in extensionTypes"
                          :value="option.value"
                          :key="option.value"
                        >
                          {{ option.text }}
                        </option>
                      </select>
                    </div>
                  </div>

                <!-- Submit/Cancel button for the modal -->
                <FormSubmit @submit="onSubmit" @close="closeModal" />
              </form>
            </DialogPanel>
          </TransitionChild>
        </div>
      </div>
    </Dialog>
  </TransitionRoot>
</template>

<script setup>
import {
  TransitionRoot,
  TransitionChild,
  Dialog,
  DialogPanel,
  DialogTitle,
  Switch,
} from "@headlessui/vue";

const props = defineProps({
  buttonTitle: {
    type: String, // title for the field
    required: false,
  },
  buttonLabel: {
    type: String, // label for the button
    required: false,
  },
});

const emits = defineEmits(["onSubmit"]);

const extension = ref({});
const showExtensionModal = useState("showExtensionModal", () => false);
const extensionTypes = useState("extensionTypes", () => [
  { value: "extensionElement", text: "Element" },
]);
const dataTypes = useState("dataTypes", () => [
  { value: "string", text: "String" },
  { value: "complex", text: "Complex" },
]);

//Open the modal on click of the button
function openModal() {
  showExtensionModal.value = true;
}

//Close the modal on click of the button
function closeModal() {
  showExtensionModal.value = false;
}

//Function to update the value of the object based on DropDown value change
function onItemChange(fieldName, value) {
  extension.value = {};
  extension.value[fieldName] = value.value;
}

//Function to store and return the value on submission
function onSubmit(event) {
  event.preventDefault();
  console.log("Sumitted : " + JSON.stringify(extension.value, null, 4));
  emits("onSubmit", extension.value);
  closeModal();
}
</script>

<style>
</style>

I am using this component twice in my application: pages/view.vue:

<template>
    <div>
  
      <div class="my-2 mx-2 px-2 pb-0">
        <div class="flex gap-2 h-16 float-right">
          <ExtensionModal
            :buttonTitle="$t('pages.modal.userExtension-btt-title')"
            :buttonLabel="$t('pages.modal.userExtension-btt-label')"
          />
  
          <ExtensionModal
            :buttonTitle="$t('pages.modal.ilmd-btt-title')"
            :buttonLabel="$t('pages.modal.ilmd-btt-label')"
          />

        </div>
      </div>
    </div>
  </template>
  
  <script setup>
  import { Icon } from "@iconify/vue";
  </script>
  
  <style>
  </style>

When I click on the button to open modal then I get the error:

There are no focusable elements inside the <FocusTrap />`

The installation and everything else is correct because it works fine when I use only one instance of the child component in my view.vue page:

<ExtensionModal
            :buttonTitle="$t('pages.modal.userExtension-btt-title')"
            :buttonLabel="$t('pages.modal.userExtension-btt-label')"
          />

I am getting the error only when i use it more than once in my application. Not sure what am I doing wrong here. Do I need to pass any additional parameter or add any missing information?

BATMAN_2008
  • 2,788
  • 3
  • 31
  • 98

0 Answers0