HoverCard ​

A floating panel that opens when the pointer rests on a trigger or the keyboard focuses it, for previews of a person or a link. For a panel that opens on click, use Popover, and for a short text hint, use Tooltip.

vue
<script setup lang="ts">
import { Avatar, HoverCard } from 'frappe-ui'
</script>

<template>
  <HoverCard>
    <template #trigger>
      <a href="#" class="text-ink-gray-9 underline underline-offset-2">
        @jane
      </a>
    </template>
    <template #default>
      <div class="flex w-64 gap-3 p-3">
        <Avatar
          label="Jane Doe"
          image="https://i.pravatar.cc/[email protected]"
          size="2xl"
        />
        <div>
          <p class="text-p-base font-medium text-ink-gray-9">Jane Doe</p>
          <p class="mt-1 text-p-sm text-ink-gray-6">
            Product designer on the Mobile team.
          </p>
        </div>
      </div>
    </template>
  </HoverCard>
</template>

Examples ​

side="top" opens the card above the link, and arrow points it back at the link.

Before you start, read the release checklist and assign yourself a step.

vue
<script setup lang="ts">
import { HoverCard } from 'frappe-ui'
</script>

<template>
  <p class="max-w-sm text-p-base text-ink-gray-8">
    Before you start, read the
    <HoverCard side="top" arrow>
      <template #trigger>
        <a
          href="#"
          class="text-ink-blue-link underline underline-offset-2"
          @click.prevent
          >release checklist</a
        >
      </template>
      <template #default>
        <div class="w-72 p-3">
          <p class="text-sm text-ink-gray-5">wiki.example.com</p>
          <p class="mt-1 text-base-medium text-ink-gray-8">Release checklist</p>
          <p class="mt-1 text-p-sm text-ink-gray-6">
            The steps to follow before every release: tests, changelog, version
            bump and the announcement.
          </p>
        </div>
      </template>
    </HoverCard>
    and assign yourself a step.
  </p>
</template>

Assignees ​

Shorter hover-delay and leave-delay values let the pointer move across a row of avatars and open each card quickly.

vue
<script setup lang="ts">
import { Avatar, HoverCard } from 'frappe-ui'

const people = [
  { name: 'Jane Cooper', email: '[email protected]', role: 'Designer' },
  { name: 'Wade Warren', email: '[email protected]', role: 'Engineer' },
  {
    name: 'Esther Howard',
    email: '[email protected]',
    role: 'Product manager',
  },
]
</script>

<template>
  <div class="flex items-center gap-1">
    <HoverCard
      v-for="person in people"
      :key="person.email"
      :hover-delay="100"
      :leave-delay="100"
    >
      <template #trigger>
        <button type="button" class="rounded-full" :aria-label="person.name">
          <Avatar
            :label="person.name"
            :image="`https://i.pravatar.cc/80?u=${person.email}`"
            size="md"
          />
        </button>
      </template>
      <template #default>
        <div class="flex w-60 items-center gap-3 p-3">
          <Avatar
            :label="person.name"
            :image="`https://i.pravatar.cc/80?u=${person.email}`"
            size="xl"
          />
          <div class="min-w-0">
            <p class="text-base-medium text-ink-gray-8">{{ person.name }}</p>
            <p class="mt-1 text-sm text-ink-gray-5">{{ person.role }}</p>
            <p class="mt-1 truncate text-sm text-ink-gray-5">
              {{ person.email }}
            </p>
          </div>
        </div>
      </template>
    </HoverCard>
  </div>
</template>

Behavior ​

Trigger and content ​

Put the trigger in #trigger and the card content in #default. Both slots receive { open, setOpen, close }, where close() is the same as setOpen(false).

Delays ​

hoverDelay is how long the pointer must rest on the trigger before the card opens. leaveDelay is how long the card waits after the pointer leaves before it closes. Both are in milliseconds, like Tooltip's, and both default to 300.

Moving into the card ​

The card stays open while the pointer is over the trigger or over the card, so people can move into the card and click a link in it.

Position ​

side, align, offset and collisionPadding work the same as on Popover.

Accessibility ​

The card also opens when the trigger gets keyboard focus. Touch screens and screen readers may never show it, so do not put an action or a fact in the card that people cannot reach another way.

API Reference ​

Show types
typescript
import type { PopoverAlign, PopoverSide } from '../Popover/types'
import type { PortalTarget } from '../../composables/usePortalTarget'

export interface HoverCardProps {
  /**
   * Side of the trigger the card is placed on.
   */
  side?: PopoverSide

  /**
   * Alignment of the card relative to the trigger.
   */
  align?: PopoverAlign

  /**
   * Distance in pixels between the card and the trigger.
   */
  offset?: number

  /**
   * Where the card is teleported to in the DOM. Unset, an embedding host's target is used, else `body`.
   */
  portalTo?: PortalTarget

  /**
   * Padding (in pixels) kept between the card and the viewport edges when
   * repositioning to avoid collisions.
   */
  collisionPadding?: number

  /**
   * Delay in milliseconds before the card opens. Default: `300`.
   */
  hoverDelay?: number

  /**
   * Delay in milliseconds before the card closes. Default: `300`.
   */
  leaveDelay?: number

  /**
   * Render a small arrow pointing at the trigger. Styled to match the panel
   * surface.
   */
  arrow?: boolean

  /** Controls the visibility of the hover card. */
  open?: boolean
}

/** Slot props passed to the `#trigger` slot. */
export interface HoverCardSlotProps {
  /** Whether the card is currently open. */
  open: boolean
  /** Sets the card open state. */
  setOpen: (value: boolean) => void
  /** Closes the card. */
  close: () => void
}

export interface HoverCardEmits {
  /** Fired when the card open state changes. */
  'update:open': [open: boolean]
}

/** Methods available on a `<HoverCard>` template ref. */
export interface HoverCardExposed {
  /** Opens the card. */
  open: () => void
  /** Closes the card. */
  close: () => void
}
side
= "bottom"
PopoverSide

Side of the trigger the card is placed on.

align
= "start"
PopoverAlign

Alignment of the card relative to the trigger.

offset
= 4
number

Distance in pixels between the card and the trigger.

portalTo
PortalTarget

Where the card is teleported to in the DOM. Unset, an embedding host's target is used, else `body`.

collisionPadding
= 10
number

Padding (in pixels) kept between the card and the viewport edges when repositioning to avoid collisions.

hoverDelay
= 300
number

Delay in milliseconds before the card opens. Default: `300`.

leaveDelay
= 300
number

Delay in milliseconds before the card closes. Default: `300`.

arrow
= false
boolean

Render a small arrow pointing at the trigger. Styled to match the panel surface.

open
= false
boolean

Controls the visibility of the hover card.

trigger
HoverCardSlotProps

Trigger element. Rendered as-child so hover/focus a11y is auto-wired.

default
HoverCardSlotProps

Card contents, rendered inside the standard PopoverPanel shell.

update:open
[value: boolean]

Fired when the open state changes.

open
() => void

Opens the card.

close
() => void

Closes the card.