Popover

A non-modal popup window for showing messages or gathering user input.

Usage

Use a Button or any other component in the default slot of the Popover.

Then, use the #content slot to add the content displayed when the Popover is open.

<template>
  <B24Popover>
    <B24Button label="Open" />

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

Mode

Use the mode prop to change the mode of the Popover. Defaults to click.

<template>
  <B24Popover mode="hover">
    <B24Button label="Open" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </B24Popover>
</template>
When using the hover mode, the Reka UI HoverCard component is used instead of the Popover.

Delay

When using the hover mode, you can use the open-delay and close-delay props to control the delay before the Popover is opened or closed.

<template>
  <B24Popover mode="hover" :open-delay="500" :close-delay="300">
    <B24Button label="Open" />

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

Content

Use the content prop to control how the Popover content is rendered, like its align or side for example.

<template>
  <B24Popover
    :content="{
      align: 'center',
      side: 'bottom',
      sideOffset: 8
    }"
  >
    <B24Button label="Open" />

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

Arrow

Use the arrow prop to display an arrow on the Popover.

<template>
  <B24Popover arrow>
    <B24Button label="Open" />

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

Use the modal prop to control whether the Popover blocks interaction with outside content. Defaults to false.

<template>
  <B24Popover modal>
    <B24Button label="Open" />

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

Dismissible

Use the dismissible prop to control whether the Popover is dismissible when clicking outside of it or pressing escape. Defaults to true.

A close:prevent event will be emitted when the user tries to close it.
<script setup lang="ts">
import Cross50Icon from '@bitrix24/b24icons-vue/actions/Cross50Icon'
</script>

<template>
  <B24Popover :dismissible="false" :b24ui="{ content: 'p-4' }">
    <B24Button label="Open" />

    <template #content="{ close }">
      <div class="flex items-center gap-4 mb-4">
        <h2 class="text-(--b24ui-typography-legend-color) font-(--ui-font-weight-semi-bold)">
          Popover non-dismissible
        </h2>

        <B24Button color="air-tertiary" :icon="Cross50Icon" @click="close" />
      </div>

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

Examples

Control open state

You can control the open state by using the default-open prop or the v-model:open directive.

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

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

<template>
  <B24Popover v-model:open="open">
    <B24Button label="Open" />

    <template #content>
      <Placeholder class="size-48 m-4 inline-flex" />
    </template>
  </B24Popover>
</template>
In this example, leveraging defineShortcuts, you can toggle the Popover by pressing O.

With command palette

You can use a CommandPalette component inside the Popover's content.

<script setup lang="ts">
import type { CommandPaletteItem } from '@bitrix24/b24ui-nuxt'
import TagIcon from '@bitrix24/b24icons-vue/outline/TagIcon'

const items = ref([
  {
    label: 'bug',
    value: 'bug',
    chip: {
      color: 'air-primary-alert'
    }
  },
  {
    label: 'feature',
    value: 'feature',
    chip: {
      color: 'air-primary-success'
    }
  },
  {
    label: 'enhancement',
    value: 'enhancement',
    chip: {
      color: 'air-primary'
    }
  }
] satisfies CommandPaletteItem[])

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

<template>
  <B24Popover :content="{ side: 'right', align: 'start' }">
    <B24Button
      :icon="TagIcon"
      label="Select labels"
    />

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

With following cursor

You can make the Popover follow the cursor when hovering over an element using the reference prop:

<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>
  <B24Popover
    :open="open"
    :reference="reference"
    :content="{ side: 'top', sideOffset: 16, updatePositionStrategy: 'always' }"
  >
    <div
      class="flex items-center justify-center rounded-md border border-dashed border-(--ui-color-accent-main-primary-alt) 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 text-(--b24ui-typography-description-color)D">
        {{ anchor.x.toFixed(0) }} - {{ anchor.y.toFixed(0) }}
      </div>
    </template>
  </B24Popover>
</template>

With anchor slot

You can use the #anchor slot to position the Popover against a custom element.

This slot only works when mode is click.
<script lang="ts" setup>
const open = ref(false)
</script>

<template>
  <B24Popover
    v-model:open="open"
    :dismissible="false"
    :b24ui="{ content: 'w-(--reka-popper-anchor-width) p-4' }"
  >
    <template #anchor>
      <B24Input placeholder="Focus to open" @focus="open = true" @blur="open = false" />
    </template>

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

API

Props

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.

arrowfalseboolean | PopoverArrowProps

Display an arrow alongside the popover.

portaltrue 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.

If not provided will use the current component as anchor.

dismissibletrueboolean

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

defaultOpenboolean

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

openboolean

The controlled open state of the popover.

modalfalseboolean

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.

openDelay0 number

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

closeDelay0 number

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

b24ui { content?: ClassNameValue; arrow?: ClassNameValue; }

Slots

Slot Type
default{ open: boolean; }
contentSlotProps<M>
anchorSlotProps<M>
The close function is only available when mode is set to click because Reka UI exposes this for Popover but not for HoverCard.

Emits

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

Theme

app.config.ts
export default defineAppConfig({
  b24ui: {
    popover: {
      slots: {
        content: 'base-mode bg-(--ui-color-bg-content-primary) shadow-(--popup-window-box-shadow) rounded-(--ui-border-radius-xl) will-change-[opacity] motion-safe:data-[state=open]:animate-[scale-in_100ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-popover-content-transform-origin) focus:outline-none pointer-events-auto',
        arrow: 'fill-(--ui-color-bg-content-primary)'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import bitrix24UIPluginVite from '@bitrix24/b24ui-nuxt/vite'

export default defineConfig({
  plugins: [
    vue(),
    bitrix24UIPluginVite({
      b24ui: {
        popover: {
          slots: {
            content: 'base-mode bg-(--ui-color-bg-content-primary) shadow-(--popup-window-box-shadow) rounded-(--ui-border-radius-xl) will-change-[opacity] motion-safe:data-[state=open]:animate-[scale-in_100ms_ease-out] motion-safe:data-[state=closed]:animate-[scale-out_100ms_ease-in] origin-(--reka-popover-content-transform-origin) focus:outline-none pointer-events-auto',
            arrow: 'fill-(--ui-color-bg-content-primary)'
          }
        }
      }
    })
  ]
})
Releases
Published under MIT License.

Copyright © 2024-present Bitrix24