Ein nicht-modaler Dialog, der um ein Triggerelement herum schwebt.

Bearbeiten

Verwenden Sie einen Button oder eine andere Komponente im Standard-Steckplatz des Popovers.

Verwenden Sie dann den #content-Steckplatz, um den Inhalt hinzuzufügen, der angezeigt wird, wenn das Popover geöffnet ist.

<template>
  <UPopover>
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>

Mode ist

Verwenden Sie die mode-prop, um den Modus des Popover. Defaults auf click zu ändern.

Stellen Sie im hover-Modus die enable-touch-Prop so ein, dass Benutzer den Popover durch Antippen des Auslösers auf Touch-Geräten umschalten können, oder verwenden Sie den click-Modus für Trigger, die angetippt werden sollen.
<template>
  <UPopover mode="hover" enable-touch>
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>
Wenn Sie den hover-Modus verwenden, wird anstelle der Komponente Popover die Reka-Benutzeroberfläche xph0444x verwendet.

Delay

Wenn Sie den hover-Modus verwenden, können Sie die open-delay-und close-delay-Props verwenden, um die Verzögerung zu steuern, bevor der Popover geöffnet oder geschlossen wird.

<template>
  <UPopover mode="hover" :open-delay="500" :close-delay="300">
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>

Inhalt

Verwenden Sie die content-Prop, um zu steuern, wie der Popover-Inhalt gerendert wird, z. B. align oder side.

<template>
  <UPopover
    :content="{
      align: 'center',
      side: 'bottom',
      sideOffset: 8
    }"
  >
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>

Arrow Bearbeiten

Verwenden Sie die arrow-Prop, um einen Pfeil auf dem Popover anzuzeigen.

<template>
  <UPopover arrow>
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>

Verwenden Sie die modal-prop, um zu steuern, ob der Popover die Interaktion mit externen Inhalten blockiert.

<template>
  <UPopover modal>
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>

Dismissible (nicht zulässig)

Verwenden Sie die dismissible-Prop, um zu steuern, ob der Popover deaktiviert werden kann, wenn Sie außerhalb des Popovers klicken oder escape drücken.

Ein close:prevent-Ereignis wird ausgelöst, wenn der Benutzer versucht, es zu schließen.
<template>
  <UPopover :dismissible="false" :ui="{ content: 'p-4' }">
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content="{ close }">
      <div class="flex items-center gap-4 mb-4">
        <h2 class="text-highlighted font-semibold">
          Popover non-dismissible
        </h2>

        <UButton color="neutral" variant="ghost" icon="i-lucide-x" @click="close" />
      </div>

      <Placeholder class="size-full min-h-48" />
    </template>
  </UPopover>
</template>

Beispiele

Control im offenen Zustand

Sie können den offenen Zustand mit der Direktive default-open prop oder der Direktive v-model:open steuern.

<script setup lang="ts">
const open = ref(false)

defineShortcuts({
  o: () => open.value = !open.value
})
</script>

<template>
  <UPopover v-model:open="open">
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>
<script setup lang="ts">
import { ref } from 'vue'

const open = ref(false)

defineShortcuts({
  o: () => open.value = !open.value
})
</script>

<template>
  <UPopover v-model:open="open">
    <UButton label="Open" color="neutral" variant="subtle" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </UPopover>
</template>
In diesem Beispiel können Sie unter Nutzung von defineShortcuts das Popover umschalten, indem Sie: kbd{value="O"}.

Mit Befehlspalette

Sie können eine CommandPalette-Komponente innerhalb des Popover-Inhalts verwenden.

<script setup lang="ts">
import type { CommandPaletteItem } from '@nuxt/ui'

const items = ref([
  {
    label: 'bug',
    value: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    value: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    value: 'enhancement',
    chip: {
      color: 'info'
    }
  }
] satisfies CommandPaletteItem[])

const label = ref([])
</script>

<template>
  <UPopover :content="{ side: 'right', align: 'start' }">
    <UButton
      icon="i-lucide-tag"
      label="Select labels"
      color="neutral"
      variant="subtle"
    />

    <template #content>
      <UCommandPalette
        v-model="label"
        multiple
        placeholder="Search labels..."
        :groups="[{ id: 'labels', items }]"
        :ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
      />
    </template>
  </UPopover>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CommandPaletteItem } from '@nuxt/ui'

const items = ref([
  {
    label: 'bug',
    value: 'bug',
    chip: {
      color: 'error'
    }
  },
  {
    label: 'feature',
    value: 'feature',
    chip: {
      color: 'success'
    }
  },
  {
    label: 'enhancement',
    value: 'enhancement',
    chip: {
      color: 'info'
    }
  }
] satisfies CommandPaletteItem[])

const label = ref([])
</script>

<template>
  <UPopover :content="{ side: 'right', align: 'start' }">
    <UButton
      icon="i-lucide-tag"
      label="Select labels"
      color="neutral"
      variant="subtle"
    />

    <template #content>
      <UCommandPalette
        v-model="label"
        multiple
        placeholder="Search labels..."
        :groups="[{ id: 'labels', items }]"
        :ui="{ input: '[&>input]:h-8 [&>input]:text-sm' }"
      />
    </template>
  </UPopover>
</template>

Mit folgendem Cursor

Sie können den Popover dazu bringen, dem Cursor zu folgen, wenn Sie mit der Prop reference über ein Element fahren:

<script setup lang="ts">
const open = ref(false)
const anchor = ref({ x: 0, y: 0 })

const reference = computed(() => ({
  getBoundingClientRect: () =>
    ({
      width: 0,
      height: 0,
      left: anchor.value.x,
      right: anchor.value.x,
      top: anchor.value.y,
      bottom: anchor.value.y,
      ...anchor.value
    } as DOMRect)
}))
</script>

<template>
  <UPopover
    :open="open"
    :reference="reference"
    :content="{ side: 'top', sideOffset: 16, updatePositionStrategy: 'always' }"
  >
    <div
      class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72"
      @pointerenter="open = true"
      @pointerleave="open = false"
      @pointermove="(ev: PointerEvent) => {
        anchor.x = ev.clientX
        anchor.y = ev.clientY
      }"
    >
      Hover me
    </div>

    <template #content>
      <div class="p-4">
        {{ anchor.x.toFixed(0) }} - {{ anchor.y.toFixed(0) }}
      </div>
    </template>
  </UPopover>
</template>
<script setup lang="ts">
import { ref, computed } from 'vue'

const open = ref(false)
const anchor = ref({ x: 0, y: 0 })

const reference = computed(() => ({
  getBoundingClientRect: () =>
    ({
      width: 0,
      height: 0,
      left: anchor.value.x,
      right: anchor.value.x,
      top: anchor.value.y,
      bottom: anchor.value.y,
      ...anchor.value
    } as DOMRect)
}))
</script>

<template>
  <UPopover
    :open="open"
    :reference="reference"
    :content="{ side: 'top', sideOffset: 16, updatePositionStrategy: 'always' }"
  >
    <div
      class="flex items-center justify-center rounded-md border border-dashed border-accented text-sm aspect-video w-72"
      @pointerenter="open = true"
      @pointerleave="open = false"
      @pointermove="(ev: PointerEvent) => {
        anchor.x = ev.clientX
        anchor.y = ev.clientY
      }"
    >
      Hover me
    </div>

    <template #content>
      <div class="p-4">
        {{ anchor.x.toFixed(0) }} - {{ anchor.y.toFixed(0) }}
      </div>
    </template>
  </UPopover>
</template>

Mit Anchor-Slot

Sie können den #anchor-Steckplatz verwenden, um das Popover gegen ein benutzerdefiniertes Element zu positionieren.

Dieser Slot funktioniert nur, wenn modeclick ist.
<script lang="ts" setup>
const open = ref(false)
</script>

<template>
  <UPopover
    v-model:open="open"
    :dismissible="false"
    :ui="{ content: 'w-(--reka-popover-trigger-width) p-4' }"
  >
    <template #anchor>
      <UInput placeholder="Focus to open" @focus="open = true" @blur="open = false" />
    </template>

    <template #content>
      <Placeholder class="w-full aspect-square" />
    </template>
  </UPopover>
</template>

API Bearbeiten

Props (englisch)

Prop Default Type
mode
'click'
M

The display mode of the popover.

content
{ side: 'bottom', sideOffset: 8, collisionPadding: 8 }
PopoverContentProps & Partial<EmitsToProps<PopoverContentImplEmits>>

The content of the popover.

arrow
false
boolean | PopoverArrowProps

Display an arrow alongside the popover. { rounded: true }

portal
true
string | false | true | HTMLElement

Render the popover in a portal.

reference
Element | VirtualElement

The reference (or anchor) element that is being referred to for positioning.

Accepts an element or a virtual element (anything with getBoundingClientRect), and can be changed reactively to re-anchor the popover (e.g. for a guided tour). If not provided will use the current component as anchor.

dismissible
true
boolean

When false, the popover will not close when clicking outside or pressing escape.

defaultOpen
boolean

The open state of the popover when it is initially rendered. Use when you do not need to control its open state.

open
boolean

The controlled open state of the popover.

modal
false
boolean

The modality of the popover. When set to true, interaction with outside elements will be disabled and only popover content will be visible to screen readers.

openDelay
0
number

The duration from when the mouse enters the trigger until the hover card opens.

closeDelay
0
number

The duration from when the mouse leaves the trigger or content until the hover card closes.

enableTouch
boolean

When true, tapping the trigger on touch devices toggles the hover card open/closed. By default touch interactions are ignored to match pointer hover semantics.

ui
{ content?: SlotClass; arrow?: SlotClass; }

Slots (englisch)

Slot Type
default
{ open: boolean; }
content
SlotProps<M>
anchor
SlotProps<M>
Die close-Funktion ist nur verfügbar, wenn mode auf click gesetzt ist, da die Reka-Benutzeroberfläche dies für Popover, nicht jedoch für HoverCard verfügbar macht.

Emits (englisch)

Event Type
close:prevent
[]
update:open
[value: boolean]

Theme Bearbeiten

app.config.ts
export default defineAppConfig({
  ui: {
    popover: {
      slots: {
        content: 'bg-default shadow-lg rounded-md ring ring-default data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)] origin-(--reka-popover-content-transform-origin) focus:outline-none pointer-events-auto',
        arrow: 'fill-bg stroke-default'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        popover: {
          slots: {
            content: 'bg-default shadow-lg rounded-md ring ring-default data-[state=open]:animate-[scale-in_100ms_var(--ease-out)] data-[state=closed]:animate-[scale-out_100ms_var(--ease-out)] origin-(--reka-popover-content-transform-origin) focus:outline-none pointer-events-auto',
            arrow: 'fill-bg stroke-default'
          }
        }
      }
    })
  ]
})

Changelog (englisch)

No recent changes