Frappe UIFrappe UI

HoverCard

Shows a floating panel when the pointer rests on (or the keyboard focuses) a trigger — for profile previews, link previews, and other sighted-only context. Built on reka-ui's HoverCard primitives.

Use HoverCard for hover-driven panels and Popover for click-driven ones. For short text hints prefer Tooltip instead.

Example

#trigger is rendered as-child, so hover and focus a11y are wired automatically. #default renders inside the standard panel shell.

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://avatars.githubusercontent.com/u/499550?v=4"
          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">
            Designer. Likes hover cards.
          </p>
        </div>
      </div>
    </template>
  </HoverCard>
</template>

Delays

hoverDelay and leaveDelay are in seconds (consistent with Tooltip). hoverDelay is how long the pointer must rest before the card opens; leaveDelay is how long after the pointer leaves before it closes.

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

<template>
  <HoverCard :hover-delay="0.1" :leave-delay="0.5">
    <template #trigger>
      <Button>Hover me</Button>
    </template>
    <template #default>
      <div class="p-3 text-p-sm text-ink-gray-7">
        Opens after 0.1s, closes 0.5s after the pointer leaves.
      </div>
    </template>
  </HoverCard>
</template>

Arrow

Set arrow to render a small arrow pointing at the trigger, styled to match the panel surface.

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

<template>
  <HoverCard side="top" arrow>
    <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://avatars.githubusercontent.com/u/499550?v=4"
          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">
            Designer. Likes hover cards.
          </p>
        </div>
      </div>
    </template>
  </HoverCard>
</template>

Styling

Like Popover, the card owns its panel shell and exposes the same stable data-slot hooks — [data-slot="content"] for the portaled content and [data-slot="content-body"] for the shell that owns the visuals. There are no class-injection props.

Motion

A hover open always uses the animated scale-from-trigger entrance (180ms in / 140ms out), and prefers-reduced-motion is respected. No configuration is required.

Notes

  • HoverCard is for sighted-only enhancement — don't put essential actions or information that can only be reached by hovering.
  • The card stays open while the pointer is over either the trigger or the card, so users can move into it to interact.

API Reference

Show types
typescript
import { type HoverCardContentProps, type HoverCardPortalProps } from 'reka-ui'

export interface HoverCardProps {
  /**
   * Side of the trigger the card is placed on.
   */
  side?: HoverCardContentProps['side']

  /**
   * Alignment of the card relative to the trigger.
   */
  align?: HoverCardContentProps['align']

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

  /**
   * Where the card is teleported to in the DOM.
   */
  portalTo?: HoverCardPortalProps['to']

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

  /**
   * Delay (in seconds) from when the pointer enters the trigger until the card
   * opens. Matches the Tooltip convention of using seconds.
   */
  hoverDelay?: number

  /**
   * Delay (in seconds) from when the pointer leaves the trigger or card until
   * the card closes.
   */
  leaveDelay?: number

  /**
   * Render a small arrow pointing at the trigger. Styled to match the panel
   * surface.
   */
  arrow?: boolean
}
side
= "bottom"
"bottom" | "top" | "right" | "left"

Side of the trigger the card is placed on.

align
= "start"
"start" | "center" | "end"

Alignment of the card relative to the trigger.

offset
= 4
number

Distance in pixels between the card and the trigger.

portalTo
= "body"
string | HTMLElement

Where the card is teleported to in the DOM.

collisionPadding
= 10
number

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

hoverDelay
= 0.3
number

Delay (in seconds) from when the pointer enters the trigger until the card opens. Matches the Tooltip convention of using seconds.

leaveDelay
= 0.3
number

Delay (in seconds) from when the pointer leaves the trigger or card until the card closes.

arrow
= false
boolean

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

open
= false
boolean
trigger
{ open: boolean; }

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

default

Card contents, rendered inside the standard PopoverPanel shell.

update:open
unknown[]

Fired when the open state changes.