"use client";
import {
Avatar,
AvatarFallback,
AvatarImage,
} from "@/components/ui/avatar";
import { Button } from "@/components/ui/button";
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card";
export function HoverCardDemo() {
return (
<HoverCard>
<HoverCardTrigger
delay={10}
closeDelay={100}
render={<Button variant="link" />}
>
@nextjs
</HoverCardTrigger>
<HoverCardContent className="w-64">
<div className="flex items-center gap-3">
<Avatar>
<AvatarImage src="https://github.com/vercel.png" />
<AvatarFallback>VC</AvatarFallback>
</Avatar>
<div className="flex flex-col gap-0.5">
<div className="font-semibold">@nextjs</div>
<div className="text-muted-foreground text-xs">
The React Framework
</div>
</div>
</div>
<div className="text-muted-foreground text-xs">
Created and maintained by @vercel.
</div>
<div className="text-muted-foreground text-xs">
Joined December 2021
</div>
</HoverCardContent>
</HoverCard>
);
}
pnpm dlx shadcn@latest add @herocn/hover-cardimport {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card"<HoverCard>
<HoverCardTrigger>Hover</HoverCardTrigger>
<HoverCardContent>
The React Framework – created and maintained by @vercel.
</HoverCardContent>
</HoverCard>Use the following composition to build a HoverCard:
HoverCard
├── HoverCardTrigger
└── HoverCardContentUse delay and closeDelay on the trigger to control when the card opens and
closes.
<HoverCard>
<HoverCardTrigger delay={100} closeDelay={200}>
Hover
</HoverCardTrigger>
<HoverCardContent>Content</HoverCardContent>
</HoverCard>Use the side and align props on HoverCardContent to control placement.
<HoverCard>
<HoverCardTrigger>Hover</HoverCardTrigger>
<HoverCardContent side="top" align="start">
Content
</HoverCardContent>
</HoverCard>Use the side prop to change the position of the hover card.
"use client";
import { Button } from "@/components/ui/button";
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card";
export function HoverCardSides() {
return (
<div className="flex flex-wrap gap-2">
{(["left", "top", "bottom", "right"] as const).map((side) => (
<HoverCard key={side}>
<HoverCardTrigger
delay={100}
closeDelay={100}
render={<Button variant="tertiary" className="w-fit capitalize" />}
>
{side}
</HoverCardTrigger>
<HoverCardContent side={side}>
<div className="flex flex-col gap-1">
<h4 className="font-medium">Hover Card</h4>
<p className="text-muted-foreground text-sm">
This hover card appears on the {side} side of the trigger.
</p>
</div>
</HoverCardContent>
</HoverCard>
))}
</div>
);
}
Use the withArrow prop to add an arrow pointing at the trigger.
"use client";
import { Button } from "@/components/ui/button";
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card";
export function HoverCardWithArrow() {
return (
<div className="flex flex-wrap gap-2">
{(["left", "top", "bottom", "right"] as const).map((side) => (
<HoverCard key={side}>
<HoverCardTrigger
delay={100}
closeDelay={100}
render={<Button variant="tertiary" className="w-fit capitalize" />}
>
{side}
</HoverCardTrigger>
<HoverCardContent withArrow side={side}>
<div className="flex flex-col gap-1">
<h4 className="font-medium">Hover Card</h4>
<p className="text-muted-foreground text-sm">
This hover card has an arrow pointing at the trigger.
</p>
</div>
</HoverCardContent>
</HoverCard>
))}
</div>
);
}
To enable RTL support in shadcn/ui, see the RTL configuration guide.
"use client";
import {
type Translations,
useTranslation,
} from "@/components/language-selector";
import { Button } from "@/components/ui/button";
import {
HoverCard,
HoverCardContent,
HoverCardTrigger,
} from "@/components/ui/hover-card";
const translations: Translations = {
en: {
dir: "ltr",
values: {
content: "The React Framework – created and maintained by @vercel.",
"inline-start": "Inline Start",
left: "Left",
top: "Top",
bottom: "Bottom",
right: "Right",
"inline-end": "Inline End",
},
},
ar: {
dir: "rtl",
values: {
content: "إطار عمل React - تم إنشاؤه وصيانته بواسطة @vercel.",
"inline-start": "بداية السطر",
left: "يسار",
top: "أعلى",
bottom: "أسفل",
right: "يمين",
"inline-end": "نهاية السطر",
},
},
he: {
dir: "rtl",
values: {
content: "React Framework - נוצר ומתוחזק על ידי @vercel.",
"inline-start": "תחילת השורה",
left: "שמאל",
top: "למעלה",
bottom: "למטה",
right: "ימין",
"inline-end": "סוף השורה",
},
},
};
const physicalSides = ["left", "top", "bottom", "right"] as const;
const logicalSides = ["inline-start", "inline-end"] as const;
export function HoverCardRtl() {
const { dir, language, t } = useTranslation(translations, "ar");
return (
<div lang={language} dir={dir} className="grid gap-4">
<div className="flex flex-wrap justify-center gap-2">
{physicalSides.map((side) => (
<HoverCard key={side}>
<HoverCardTrigger
delay={10}
closeDelay={100}
render={<Button variant="tertiary" />}
>
{t[side]}
</HoverCardTrigger>
<HoverCardContent side={side} dir={dir} className="w-64">
<div className="font-semibold">@nextjs</div>
<div className="text-muted-foreground text-sm">{t.content}</div>
</HoverCardContent>
</HoverCard>
))}
</div>
<div className="flex flex-wrap justify-center gap-2">
{logicalSides.map((side) => (
<HoverCard key={side}>
<HoverCardTrigger
delay={10}
closeDelay={100}
render={<Button variant="tertiary" />}
>
{t[side]}
</HoverCardTrigger>
<HoverCardContent side={side} dir={dir} className="w-64">
<div className="font-semibold">@nextjs</div>
<div className="text-muted-foreground text-sm">{t.content}</div>
</HoverCardContent>
</HoverCard>
))}
</div>
</div>
);
}
The hover card is built on Base UI PreviewCard. HoverCardContent sets default positioning and passes the remaining props to the popup.
| Prop | Type | Default |
|---|---|---|
| align | "start" | "center" | "end" | "center" |
| alignOffset | number | 8 |
| side | "top" | "bottom" | "left" | "right" | "inline-start" | "inline-end" | "bottom" |
| sideOffset | number | 8 |
| withArrow | boolean | false |
See the Base UI PreviewCard API reference for root, trigger, and other props.