ironman33
ironman33

Reputation: 21

How can I open a modal in a popover dropdown and the popover closes and the modal teleports to the body of the page?

I am using VueJS, along with tailwind css and headless ui to create a popover dropdown that contains a modal.
When the modal is selected out of the dropdown, the dropdown should close, and the modal appear.

Currently the modal does appear, but with the dropdown still showing behind of it. The popover dropdown code is in the parent component, and the modal code is in the child component (<base-subscriptions>).

How can I select the modal out of the dropdown, where the dropdown closes, and the modal appears?

The parent component:

<template>
  <Popover class="relative bg-white">
    <div class="mx-auto max-w-7xl px-4 sm:px-6">
      <div class="flex items-center justify-between border-b-2 border-gray-100 py-6 md:justify-start md:space-x-10">
        <PopoverGroup as="nav" class="hidden space-x-10 md:flex">
          <Popover class="relative" v-slot="{ open }">
            <PopoverButton
              :class="[
                open ? 'text-gray-900' : 'text-gray-500',
                'group inline-flex items-center rounded-md bg-white text-base font-medium hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:ring-offset-2'
              ]"
            >
              <span>Solutions</span>
              <ChevronDownIcon
                :class="[open ? 'text-gray-600' : 'text-gray-400', 'ml-2 h-5 w-5 group-hover:text-gray-500']"
                aria-hidden="true"
              />
            </PopoverButton>

            <transition
              enter-active-class="transition ease-out duration-200"
              enter-from-class="opacity-0 translate-y-1"
              enter-to-class="opacity-100 translate-y-0"
              leave-active-class="transition ease-in duration-150"
              leave-from-class="opacity-100 translate-y-0"
              leave-to-class="opacity-0 translate-y-1"
            >
              <PopoverPanel
                class="absolute z-10 -ml-4 mt-3 w-screen max-w-md transform px-2 sm:px-0 lg:left-1/2 lg:ml-0 lg:-translate-x-1/2"
              >
                <div class="overflow-hidden rounded-lg shadow-lg ring-1 ring-black ring-opacity-5">
                  <div class="relative grid gap-6 bg-white px-5 py-6 sm:gap-8 sm:p-8"></div>
                  <div class="space-y-6 bg-gray-50 px-5 py-5 sm:flex sm:space-y-0 sm:space-x-10 sm:px-8">
                    <subscriptions-modal></subscriptions-modal>
                  </div>
                </div>
              </PopoverPanel>
            </transition>
          </Popover>
        </PopoverGroup>
      </div>
    </div>
  </Popover>
</template>

<script setup>
import { Popover, PopoverButton, PopoverGroup, PopoverPanel } from '@headlessui/vue'
import { ChevronDownIcon } from '@heroicons/vue/20/solid'
import SubscriptionsModal from './SubscriptionsModal'
</script>    

The subscriptions modal child component:

<template>
  <button @click="isOpen = true" type="button">
    <a v-for="item in subscriptions" :key="item.name" class="-m-3 flex items-start rounded-lg p-3 hover:bg-gray-50">
      <component :is="item.icon" class="h-6 w-6 flex-shrink-0 text-blue-600" aria-hidden="true" />
      <div class="ml-4">
        <p class="text-left text-base font-medium text-gray-900">{{ item.name }}</p>
        <p class="mt-1 text-sm text-gray-500">{{ item.description }}</p>
      </div>
    </a>
  </button>

  <teleport to="body">
    <div v-show="isOpen" class="absolute inset-0 flex items-center justify-center bg-gray-700 bg-opacity-50 z-10">
      <div class="max-w-2xl p-6 mx-4 bg-white rounded-md shadow-xl">
        <div class="w-full max-w-md space-y-8 flex flex-col">
          <div class="self-end items-center justify-between">
            <svg
              @click="isOpen = false"
              xmlns="http://www.w3.org/2000/svg"
              class="w-8 h-8 text-red-900 cursor-pointer self-end"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path
                stroke-linecap="round"
                stroke-linejoin="round"
                stroke-width="2"
                d="M10 14l2-2m0 0l2-2m-2 2l-2-2m2 2l2 2m7-2a9 9 0 11-18 0 9 9 0 0118 0z"
              />
            </svg>
          </div>
          <img class="mx-auto h-12 w-auto" />
          <h2 class="mt-6 text-center text-3xl font-bold tracking-tight text-gray-900">Active Subscriptions</h2>
          <form class="mt-8 space-y-6" action="#" method="POST">
            <input type="hidden" name="remember" value="true" />
            <div class="text-center">
              <p class="formText">No current subscriptions</p>
            </div>
          </form>
        </div>
      </div>
    </div>
  </teleport>
</template>
<script setup>
import { CheckBadgeIcon } from '@heroicons/vue/24/outline';
import { ref } from 'vue';
let isOpen = ref(false);

const subscriptions = [
  {
    name: 'Subscriptions',
    description: 'Please see who all has subscribed to our dashboards',
    icon: CheckBadgeIcon,
  }
]
</script>

Upvotes: 1

Views: 515

Answers (1)

Mahdi Arjangi
Mahdi Arjangi

Reputation: 41

You can do this by following the installation instructions provided in the package's GitHub repository: headless-flot GitHub repository.

Upvotes: 0

Related Questions