Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using a custom Portal component #38

Closed
ragulka opened this issue Jan 13, 2023 · 2 comments
Closed

Using a custom Portal component #38

ragulka opened this issue Jan 13, 2023 · 2 comments
Labels
bug Something isn't working

Comments

@ragulka
Copy link

ragulka commented Jan 13, 2023

Use Version
Use version when question appear:

  • Headless UI: v1.7.7
  • Headless UI Float: v0.10.1
  • Framework: [vue v3.2.33]

Describe the question
I'm trying to render a HeadlessUI Combobox inside a Popover. For this, I need to teleport the combobox options to the body, so that the dropdown options can overflow the popover, and the popover won't show scrollbars.

However, there's an issue - when clicking any of the combobox options, the popover is immediately closed. I believe it is because of the click outside handler, which now sees the options as being rendered outside of the popover. I saw a mention in HeadlessUI repo that using the Portal from @headlessui/vue instead of the regular Teleport component should help with this. Unfortunately, I don't see that it's possible to customize the portal component for Float. Would you consider supporting something like that? Or perhaps there's another solution to the issue?

Screenshots
If applicable, add screenshots to help explain your problem.

@ragulka ragulka added the question Ask question label Jan 13, 2023
@ycs77
Copy link
Owner

ycs77 commented Feb 3, 2023

Hi @ragulka, can you provide a minimal reproducible question example (like github repo, codesandbox, stackblitz...) for me to debug 😅? I will refer to your suggestion and try to find a solution.

@ycs77 ycs77 added needs more info Need more information bug Something isn't working need MWE and removed question Ask question needs more info Need more information labels Feb 3, 2023
@ycs77 ycs77 removed the need MWE label Mar 10, 2023
@ycs77
Copy link
Owner

ycs77 commented Mar 11, 2023

Hi @ragulka, I think this can be broken down into two parts.

First, regarding the change of Teleport to use the <Portal> component of Headless UI, I have already modified it and released it to v0.11, thank you for your reminder.

Second, if you want to use Popover and Combobox, you don’t need to use the portal, here is an example for you to test:

<template>
  <Popover v-slot="{ close }">
    <Float
      placement="bottom-start"
      :offset="15"
      :shift="6"
      :flip="10"
      arrow
      enter="transition duration-200 ease-out"
      enter-from="opacity-0 -translate-y-1"
      enter-to="opacity-100 translate-y-0"
      leave="transition duration-150 ease-in"
      leave-from="opacity-100 translate-y-0"
      leave-to="opacity-0 -translate-y-1"
    >
      <PopoverButton class="px-3 py-1.5 flex justify-center items-center bg-rose-50 hover:bg-rose-100 text-rose-500 rounded">
        Open
      </PopoverButton>

      <PopoverPanel class="w-[240px] bg-white border border-gray-200 rounded-md shadow-lg focus:outline-none">
        <FloatArrow class="absolute bg-white w-5 h-5 rotate-45 border border-gray-200" />

        <div class="relative p-3 bg-white rounded-md">
          <label class="inline-block mb-1">Combobox</label>
          <Combobox v-model="selected">
            <Float
              as="div"
              class="relative"
              placement="bottom-start"
              :offset="4"
              leave="transition ease-in duration-100"
              leave-from="opacity-100"
              leave-to="opacity-0"
              floating-as="template"
              @hide="query = ''"
            >
              <div class="relative w-full text-left bg-white border border-gray-200 rounded-lg shadow-md cursor-default focus:outline-none sm:text-sm overflow-hidden">
                <ComboboxInput
                  class="w-full border-none py-2 pl-3 pr-10 text-sm leading-5 text-gray-900 focus:outline-none focus:ring-0"
                  :display-value="person => person?.name"
                  @change="query = $event.target.value"
                />

                <ComboboxButton class="absolute inset-y-0 right-0 flex items-center pr-2">
                  <HeroiconsChevronUpDown20Solid class="w-5 h-5 text-gray-400" aria-hidden="true" />
                </ComboboxButton>
              </div>

              <ComboboxOptions class="absolute w-full py-1 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
                <div
                  v-if="filteredPeople.length === 0 && query !== ''"
                  class="relative py-2 px-4 text-gray-700 cursor-default select-none"
                >
                  Nothing found.
                </div>

                <ComboboxOption
                  v-for="person in filteredPeople"
                  v-slot="{ selected, active }"
                  :key="person.id"
                  :value="person"
                  as="template"
                >
                  <li
                    class="relative py-2 pl-10 pr-4 cursor-default select-none"
                    :class="active ? 'text-white bg-rose-600' : 'text-gray-900'"
                  >
                    <span class="block truncate" :class="selected ? 'font-medium' : 'font-normal'">
                      {{ person.name }}
                    </span>
                    <span
                      v-if="selected"
                      class="absolute inset-y-0 left-0 flex items-center pl-3"
                      :class="active ? 'text-white' : 'text-rose-600'"
                    >
                      <HeroiconsCheck20Solid class="w-5 h-5" aria-hidden="true" />
                    </span>
                  </li>
                </ComboboxOption>
              </ComboboxOptions>
            </Float>
          </Combobox>

          <div class="mt-4 flex justify-end">
            <button type="button" class="px-4 py-1 bg-rose-500 text-white text-sm rounded" @click="close">
              Submit
            </button>
          </div>
        </div>
      </PopoverPanel>
    </Float>
  </Popover>
</template>

<script setup>
import { computed, ref } from 'vue'
import { Combobox, ComboboxButton, ComboboxInput, ComboboxOption, ComboboxOptions, Popover, PopoverButton, PopoverPanel } from '@headlessui/vue'
import { Float, FloatArrow } from '@headlessui-float/vue'
import HeroiconsCheck20Solid from '~icons/heroicons/check-20-solid'
import HeroiconsChevronUpDown20Solid from '~icons/heroicons/chevron-up-down-20-solid'

const people = [
  { id: 1, name: 'Wade Cooper' },
  { id: 2, name: 'Arlene Mccoy' },
  { id: 3, name: 'Devon Webb' },
  { id: 4, name: 'Tom Cook' },
  { id: 5, name: 'Tanya Fox' },
  { id: 6, name: 'Hellen Schmidt' },
]
const selected = ref(people[0])
const query = ref('')

const filteredPeople = computed(() =>
  query.value === ''
    ? people
    : people.filter(person =>
      person.name
        .toLowerCase()
        .replace(/\s+/g, '')
        .includes(query.value.toLowerCase().replace(/\s+/g, ''))
    )
)
</script>

If you have other questions, open a new issue and attach your sample code or minimally reproducible GitHub project. Online demo is provided here to test <Float> at any time.

@ycs77 ycs77 closed this as completed Mar 11, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants