HextaUI

Hover card: Shared card

One card serves many links. Create a handle with createHoverCardHandle, give each trigger a payload, and read it in the card. Moving between names glides the card to the new link instead of closing and reopening it. The old content slides out the way you moved, the new content slides in, and the height eases between the two.

"use client"

import { Avatar, AvatarFallback } from "@/components/ui/avatar"
import {
  createHoverCardHandle,
  HoverCard,
  HoverCardContent,
  HoverCardTrigger,
} from "@/components/ui/hover-card"

type Person = { name: string; initials: string; role: string }

const team: Person[] = [
  { name: "Ada Lovelace", initials: "AL", role: "Analyst" },
  { name: "Alan Turing", initials: "AT", role: "Research" },
  { name: "Grace Hopper", initials: "GH", role: "Compilers" },
]

const profileCard = createHoverCardHandle<Person>()

export function HoverCardDetached() {
  return (
    <div className="flex flex-col items-center gap-3">
      <ul className="flex flex-col items-start gap-2 text-sm">
        {team.map((person) => (
          <li key={person.name}>
            <HoverCardTrigger
              handle={profileCard}
              payload={person}
              href="#"
              delay={300}
              render={
                <a className="font-medium underline decoration-border underline-offset-4 hover:decoration-foreground" />
              }
            >
              {person.name}
            </HoverCardTrigger>
          </li>
        ))}
      </ul>
      <HoverCard handle={profileCard}>
        {({ payload }) => (
          <HoverCardContent side="inline-end" align="start" className="w-56">
            {payload ? (
              <div className="flex items-center gap-3">
                <Avatar>
                  <AvatarFallback>{payload.initials}</AvatarFallback>
                </Avatar>
                <div className="flex min-w-0 flex-col">
                  <p className="font-medium">{payload.name}</p>
                  <p className="text-muted-foreground">{payload.role}</p>
                </div>
              </div>
            ) : null}
          </HoverCardContent>
        )}
      </HoverCard>
    </div>
  )
}

This adds the example as components/examples/hover-card/detached.tsx, together with the Hover card component and the HextaUI theme tokens it needs.

pnpm dlx shadcn@latest add https://hextaui.com/r/hover-card-detached.json

To add only the component, follow the Hover card installation.

Props in this example

The Hover card props this example sets, from the API reference.

PropTypeDefault
handleConnects triggers rendered outside the root.
HoverCardHandle<Payload>–
PropTypeDefault
href
string–
delayMilliseconds before hover or focus opens the card.
number600
handle
HoverCardHandle<Payload>–
payloadPassed to the card when this trigger opens it.
Payload–
renderRender your own link, such as <Button variant="link" /> or a router link.
ReactElement | (props, state) => ReactElement<a>
PropTypeDefault
side
"top" | "bottom" | "left" | "right" | "inline-start" | "inline-end""bottom"
align
"start" | "center" | "end""center"

Every prop is in the Hover card API reference.

See them all, with keyboard support and accessibility notes, on the Hover card page.