A premium hover/focus popover for quick previews — users, files and extra details — with blur entrance, an animated arrow and staggered content.
Reviewed by @sofia and attached to the thread.
"use client";
import {
Calendar,
Download,
FileText,
MapPin,
Star,
UserPlus,
} from "lucide-react";
import {
PopoverCard,
PopoverCardBody,
PopoverCardContent,
PopoverCardDescription,
PopoverCardFooter,
PopoverCardHeader,
PopoverCardItem,
PopoverCardTitle,
PopoverCardTrigger,
} from "@/components/matos-ui/popover-card";
export function PopoverCardDemo() {
return (
<div className="flex min-h-52 w-full max-w-md flex-col items-center justify-center gap-10">
<p className="text-center text-muted-foreground text-sm leading-relaxed">
Reviewed by{" "}
<PopoverCard>
<PopoverCardTrigger underline className="font-medium text-foreground">
@sofia
</PopoverCardTrigger>
<PopoverCardContent side="top">
<PopoverCardHeader>
<span className="flex size-11 shrink-0 items-center justify-center rounded-full bg-gradient-to-br from-chart-1/30 to-chart-4/30 font-semibold text-foreground text-sm ring-1 ring-border">
SR
</span>
<div className="min-w-0">
<PopoverCardTitle>Sofia Ramos</PopoverCardTitle>
<PopoverCardDescription>
Lead Product Designer
</PopoverCardDescription>
</div>
</PopoverCardHeader>
<PopoverCardBody>
Crafting the design system and obsessing over micro-interactions.
</PopoverCardBody>
<PopoverCardItem className="flex flex-wrap gap-x-4 gap-y-1.5 text-muted-foreground text-xs">
<span className="inline-flex items-center gap-1.5">
<MapPin className="size-3.5" aria-hidden="true" />
Lisbon, PT
</span>
<span className="inline-flex items-center gap-1.5">
<Calendar className="size-3.5" aria-hidden="true" />
Joined 2021
</span>
</PopoverCardItem>
<PopoverCardFooter>
<button
type="button"
className="inline-flex h-8 flex-1 items-center justify-center gap-1.5 rounded-lg bg-primary font-medium text-primary-foreground text-xs shadow-xs transition-[transform,background-color] duration-200 hover:bg-primary/90 active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
<UserPlus className="size-3.5" aria-hidden="true" />
Follow
</button>
<button
type="button"
className="inline-flex h-8 items-center justify-center gap-1.5 rounded-lg border border-border bg-background px-3 font-medium text-foreground text-xs transition-colors duration-200 hover:bg-muted/60 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
Message
</button>
</PopoverCardFooter>
</PopoverCardContent>
</PopoverCard>{" "}
and attached{" "}
<PopoverCard>
<PopoverCardTrigger
render={
<button
type="button"
className="inline-flex items-center gap-1.5 rounded-lg border border-border bg-muted/40 px-2 py-0.5 font-medium text-foreground text-xs"
/>
}
>
<FileText className="size-3.5" aria-hidden="true" />
report.pdf
</PopoverCardTrigger>
<PopoverCardContent size="sm">
<PopoverCardHeader>
<span className="flex size-10 shrink-0 items-center justify-center rounded-xl bg-destructive/10 text-destructive ring-1 ring-destructive/20">
<FileText className="size-5" aria-hidden="true" />
</span>
<div className="min-w-0">
<PopoverCardTitle className="truncate">
report.pdf
</PopoverCardTitle>
<PopoverCardDescription>
2.4 MB · Updated today
</PopoverCardDescription>
</div>
</PopoverCardHeader>
<PopoverCardItem className="flex items-center gap-1.5 text-muted-foreground text-xs">
<Star
className="size-3.5 fill-chart-4 text-chart-4"
aria-hidden="true"
/>
Shared with 4 people
</PopoverCardItem>
<PopoverCardFooter>
<button
type="button"
className="inline-flex h-8 w-full items-center justify-center gap-1.5 rounded-lg border border-border bg-background font-medium text-foreground text-xs transition-[transform,background-color] duration-200 hover:bg-muted/60 active:scale-[0.98] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
>
<Download className="size-3.5" aria-hidden="true" />
Download
</button>
</PopoverCardFooter>
</PopoverCardContent>
</PopoverCard>{" "}
to the thread.
</p>
</div>
);
}
pnpm dlx shadcn@latest add https://matos-ui.com/r/popover-card.jsonimport {
PopoverCard,
PopoverCardTrigger,
PopoverCardContent,
PopoverCardHeader,
PopoverCardTitle,
PopoverCardDescription,
PopoverCardBody,
PopoverCardFooter,
PopoverCardItem
} from '@/components/matos-ui/popover-card'<PopoverCard>
<PopoverCardTrigger underline>@sofia</PopoverCardTrigger>
<PopoverCardContent side="top">
<PopoverCardHeader>
<PopoverCardTitle>Sofia Ramos</PopoverCardTitle>
<PopoverCardDescription>Product Designer</PopoverCardDescription>
</PopoverCardHeader>
<PopoverCardBody>Crafting the design system.</PopoverCardBody>
</PopoverCardContent>
</PopoverCard>The card opens on hover and on keyboard focus, so it works for pointer and keyboard users alike. It is built on Base UI's Preview Card, so positioning, collision handling, portalling and focus management come for free.
Reach for the Popover Card to surface non-essential, contextual information without navigating away:
For information the user must act on, use a dialog or popover with a click trigger instead.
The trigger renders an <a> by default. Use the render prop to turn any
element (a button, an avatar) into the trigger.
<PopoverCardTrigger
render={<button type="button" className="rounded-lg border px-2 py-0.5" />}
>
report.pdf
</PopoverCardTrigger><PopoverCardContent side="right" align="start" size="lg" sideOffset={12}>
...
</PopoverCardContent>delay and closeDelay live on the trigger (in milliseconds).
<PopoverCardTrigger delay={200} closeDelay={120}>
Hover me
</PopoverCardTrigger>Header, Body, Footer and Item rise and
de-blur one after another via Framer Motion.Wraps Base UI PreviewCard.Root. Accepts open, defaultOpen and
onOpenChange for controlled usage.
| Prop | Type | Default | Description |
|---|---|---|---|
render | element | <a> | Render the trigger as a different element. |
underline | boolean | false | Dotted underline styling for inline text triggers. |
delay | number | 600 | Time to wait before opening (ms). |
closeDelay | number | 300 | Time to wait before closing (ms). |
| Prop | Type | Default | Description |
|---|---|---|---|
size | "sm" | "md" | "lg" | "md" | Width of the card. |
side | "top" | "right" | "bottom" | "left" | "bottom" | Preferred side relative to the trigger. |
align | "start" | "center" | "end" | "center" | Alignment along the side. |
sideOffset | number | 10 | Gap between trigger and card. |
alignOffset | number | 0 | Offset along the alignment axis. |
showArrow | boolean | true | Render the animated arrow. |
| Component | Description |
|---|---|
PopoverCardHeader | Staggered row, ideal for an avatar + title block. |
PopoverCardTitle | Primary label. |
PopoverCardDescription | Muted secondary label. |
PopoverCardBody | Staggered body text block. |
PopoverCardItem | Generic staggered row for custom content. |
PopoverCardFooter | Staggered footer with a top divider for actions. |
Also exported: popoverCardTriggerVariants and popoverCardPopupVariants.
side="top" for triggers near the bottom of the viewport.Install Matos UI
Choose a package manager and copy one command for every component.