UIPackage

Hover Card

Vue overlay
Edit on GitHub

Rich popover triggered by hover/focus instead of click. Use for inline previews — user cards on @mentions, link previews, KPI explanations. Built on reka-ui with a configurable open/close delay.

Also available for React ->

Installation

$ npx shadcn-vue@latest add https://uipkge.dev/r/vue/hover-card.json

Or with the named registry: npx shadcn-vue@latest add @uipkge/hover-card

Examples

Dependencies

Files (4)

  • app/components/ui/hover-card/HoverCard.vue 0.5 kB
    <script setup lang="ts">
    import type { HoverCardRootEmits, HoverCardRootProps } from 'reka-ui'
    import { HoverCardRoot, useForwardPropsEmits } from 'reka-ui'
    
    const props = defineProps<HoverCardRootProps>()
    const emits = defineEmits<HoverCardRootEmits>()
    
    const forwarded = useForwardPropsEmits(props, emits)
    </script>
    
    <template>
      <HoverCardRoot v-slot="slotProps" data-uipkge data-slot="hover-card" v-bind="forwarded">
        <slot v-bind="slotProps" />
      </HoverCardRoot>
    </template>
  • app/components/ui/hover-card/HoverCardContent.vue 1.4 kB
    <script setup lang="ts">
    import type { HoverCardContentProps } from 'reka-ui'
    import type { HTMLAttributes } from 'vue'
    import { reactiveOmit } from '@vueuse/core'
    import { HoverCardContent, HoverCardPortal, useForwardProps } from 'reka-ui'
    import { cn } from '@/lib/utils'
    
    defineOptions({
      inheritAttrs: false,
    })
    
    const props = withDefaults(defineProps<HoverCardContentProps & { class?: HTMLAttributes['class'] }>(), {
      sideOffset: 4,
    })
    
    const delegatedProps = reactiveOmit(props, 'class')
    
    const forwardedProps = useForwardProps(delegatedProps)
    </script>
    
    <template>
      <HoverCardPortal>
        <HoverCardContent
          data-uipkge
          data-slot="hover-card-content"
          v-bind="{ ...$attrs, ...forwardedProps }"
          :class="
            cn(
              'bg-popover text-popover-foreground motion-safe:data-[state=open]:animate-in motion-safe:data-[state=closed]:animate-out motion-safe:data-[state=closed]:fade-out-0 motion-safe:data-[state=open]:fade-in-0 motion-safe:data-[state=closed]:zoom-out-95 motion-safe:data-[state=open]:zoom-in-95 motion-safe:data-[side=bottom]:slide-in-from-top-2 motion-safe:data-[side=left]:slide-in-from-right-2 motion-safe:data-[side=right]:slide-in-from-left-2 motion-safe:data-[side=top]:slide-in-from-bottom-2 z-50 w-64 rounded-md border p-4 shadow-md outline-hidden',
              props.class,
            )
          "
        >
          <slot />
        </HoverCardContent>
      </HoverCardPortal>
    </template>
  • app/components/ui/hover-card/HoverCardTrigger.vue 0.3 kB
    <script setup lang="ts">
    import type { HoverCardTriggerProps } from 'reka-ui'
    import { HoverCardTrigger } from 'reka-ui'
    
    const props = defineProps<HoverCardTriggerProps>()
    </script>
    
    <template>
      <HoverCardTrigger data-uipkge data-slot="hover-card-trigger" v-bind="props">
        <slot />
      </HoverCardTrigger>
    </template>
  • app/components/ui/hover-card/index.ts 0.2 kB
    export { default as HoverCard } from './HoverCard.vue'
    export { default as HoverCardContent } from './HoverCardContent.vue'
    export { default as HoverCardTrigger } from './HoverCardTrigger.vue'

Raw manifest: https://uipkge.dev/r/vue/hover-card.json