hover-card
For sighted users to preview content available behind a link.
Philosophy
Hover cards provide progressive disclosure without commitment. They let users preview content before clicking, reducing unnecessary navigation. We build on Popover primitives because hover cards are fundamentally popovers with mouse-enter triggers - shared internals mean consistent behavior and smaller bundle size.
How It's Built
Installation
npx @gentleduck/cli add hover-card
npx @gentleduck/cli add hover-card
Usage
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card"
<HoverCard>
<HoverCardTrigger>Hover</HoverCardTrigger>
<HoverCardContent>
The React Framework - created and maintained by @vercel.
</HoverCardContent>
</HoverCard>
Examples
Active Trigger on Open
Style the trigger to appear active while the hover card is open using data-[state=open]:
Arrow
Add a caret pointing at the trigger. The arrow moves along the content edge when collision avoidance shifts the card near a viewport boundary.
RTL Support
Set the direction once with DirectionProvider (or <html dir="rtl">) and the hover card follows. The portaled content gets the resolved dir, and side="left"/side="right" and align="start"/align="end" mirror with it.
<DirectionProvider dir="rtl">
<HoverCard>
<HoverCardTrigger>مرّر المؤشر</HoverCardTrigger>
<HoverCardContent>محتوى البطاقة هنا.</HoverCardContent>
</HoverCard>
</DirectionProvider>
Motion
Use MotionHoverCard and MotionHoverCardContent for smooth enter/exit animations powered by motion. The card scales and fades with a directional shift matching the placement side.
motion package. Use MotionHoverCard instead of HoverCard and MotionHoverCardContent instead of HoverCardContent. HoverCardTrigger stays the same.API Reference
HoverCard
Root wrapper that provides hover-card state and context. Wraps HoverCardPrimitive.Root internally.
| Prop | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state |
onOpenChange | (open: boolean) => void | - | Callback when open state changes |
defaultOpen | boolean | - | Initial open state for uncontrolled usage |
openDelay | number | 700 | Delay before opening on hover/focus |
closeDelay | number | 300 | Delay before closing on pointer leave/blur |
delayDuration | number | - | Alias for openDelay. If both are provided, openDelay takes precedence |
skipDelayDuration | number | - | Reserved for future use (currently ignored) |
placement | 'top' | 'right' | 'bottom' | 'left' | 'top' | Accepted but has no effect on the base HoverCard/HoverCardContent pairing; only takes effect with MotionHoverCard/MotionHoverCardContent, which read it via context to pick the entrance direction |
dir | 'ltr' | 'rtl' | - | Optional override. Resolved by primitives useDirection (dir prop -> DirectionProvider -> <html dir>). |
children | React.ReactNode | -- | HoverCard sub-components |
...props | React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Root> | - | Additional props inherited from HoverCard.Root. |
HoverCardTrigger
The element that triggers the hover card on hover. Applies buttonVariants styling.
| Prop | Type | Default | Description |
|---|---|---|---|
variant | ButtonVariant | 'outline' | Button variant style |
size | ButtonSize | 'default' | Button size |
border | ButtonBorder | 'default' | Button border style |
children | React.ReactNode | -- | Content rendered inside the trigger button |
...props | React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Trigger> & Variants.VariantProps<typeof buttonVariants> | - | Additional props inherited from HoverCard.Trigger. Always renders a native a element; there is no asChild/Slot support. |
HoverCardContent
The content displayed when the hover card is open. Wraps HoverCardPrimitive.Content with animation and styling.
| Prop | Type | Default | Description |
|---|---|---|---|
className | string | - | Additional CSS classes to apply to the content container |
children | React.ReactNode | - | Content rendered inside the hover card |
forceMount | boolean | - | Keep content mounted for animation control |
side | 'top' | 'right' | 'bottom' | 'left' | 'top' | Preferred side relative to the trigger. Defaults to the placement value from HoverCard |
align | 'start' | 'center' | 'end' | 'center' | Alignment on the chosen side |
sideOffset | number | 4 | Main-axis offset from trigger |
alignOffset | number | 0 | Cross-axis offset from trigger |
...props | React.ComponentPropsWithoutRef<typeof HoverCardPrimitive.Content> & React.HTMLProps<HTMLDivElement> | - | Additional props inherited from HoverCard.Content and standard content div props. |
MotionHoverCard
Wraps with useMotionRoot for exit animation support. Requires the motion package.
| Prop | Type | Default | Description |
|---|---|---|---|
placement | 'top' | 'right' | 'bottom' | 'left' | 'top' | Provided via context to MotionHoverCardContent, which uses it as the default entrance/exit direction when its own side prop is unset. This is where placement actually takes effect. |
...props | HoverCardProps | - | All props from HoverCard are supported |
MotionHoverCardContent
Adds directional scale, blur, and opacity enter/exit animation. Requires the motion package.
| Prop | Type | Default | Description |
|---|---|---|---|
...props | HoverCardContentProps | - | All props from HoverCardContent are supported |