Installation
pnpm dlx shadcn@latest add https://rdf.dev.360online.com/r/hover-card.jsonInstalls to @/components/ui/hover-card.
Manual installation
Install the dependencies:
pnpm add @base-ui/react@^1.8.0Copy the source into your project:
'use client'
import { PreviewCard as PreviewCardPrimitive } from '@base-ui/react/preview-card'
import { cn } from '@/lib/utils'
function HoverCard({ ...props }: PreviewCardPrimitive.Root.Props) {
return <PreviewCardPrimitive.Root data-slot="hover-card" {...props} />
}
function HoverCardTrigger({ ...props }: PreviewCardPrimitive.Trigger.Props) {
return <PreviewCardPrimitive.Trigger data-slot="hover-card-trigger" {...props} />
}
function HoverCardContent({
className,
side = 'bottom',
sideOffset = 4,
align = 'center',
alignOffset = 4,
...props
}: PreviewCardPrimitive.Popup.Props &
Pick<PreviewCardPrimitive.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>) {
return (
<PreviewCardPrimitive.Portal data-slot="hover-card-portal">
<PreviewCardPrimitive.Positioner
align={align}
alignOffset={alignOffset}
side={side}
sideOffset={sideOffset}
className="isolate z-50"
>
<PreviewCardPrimitive.Popup
data-slot="hover-card-content"
className={cn(
'z-50 w-64 origin-(--transform-origin) rounded-lg bg-popover p-2.5 text-sm text-popover-foreground shadow-md ring-1 ring-foreground/10 outline-hidden duration-100 data-[side=bottom]:slide-in-from-top-2 data-[side=inline-end]:slide-in-from-left-2 data-[side=inline-start]:slide-in-from-right-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95',
className,
)}
{...props}
/>
</PreviewCardPrimitive.Positioner>
</PreviewCardPrimitive.Portal>
)
}
export { HoverCard, HoverCardTrigger, HoverCardContent }For sighted users to preview content available behind a link, such as a person, a case or a document. Built on Base UI PreviewCard, the card opens on hover or keyboard focus after a short delay.
Features
- Opens on hover and focus
- Configurable open and close delays (
delayandcloseDelayonHoverCardTrigger) - Pass the trigger element with
render(e.g.render={<a href="…" />}); the trigger renders an<a>by default - Positioning on any side with alignment and offset
- Rendered in a portal with enter and exit animations
Usage
import { Button } from '@/components/ui/button'
import { HoverCard, HoverCardContent, HoverCardTrigger } from '@/components/ui/hover-card'
export function OfficerPreview() {
return (
<HoverCard>
<HoverCardTrigger delay={200} render={<Button variant="link" />}>@anna.lindqvist</HoverCardTrigger>
<HoverCardContent>Case officer, Planning and Building Department.</HoverCardContent>
</HoverCard>
)
}Examples
Default
An inline link to a case officer that previews their role and contact details.
Case Preview
An inline case link that previews status, registration date and number of documents.
Facility Preview
A button trigger that previews a library’s opening hours, opening above the trigger.
Sides
Cards opening on each side of the trigger.
Accessibility
- Hover cards are ignored by screen readers; do not put essential information only in the card
- The trigger should be a link or button so it can receive keyboard focus
- Avoid interactive content that users must reach from the card
- Use Popover instead when the content must be accessible on touch devices