# Hover Card

A preview of the record behind a link, shown when the pointer rests on the link.

```tsx
import { Badge } from "@zenoxai/ui/components/badge"
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@zenoxai/ui/components/hover-card"

function HoverCardDemo() {
  return (
    <p>
      Alert raised on{" "}
      <HoverCard>
        <HoverCardTrigger
          href="#asset-srv-db-01"
          className="font-medium text-link underline-offset-4 hover:underline"
        >
          srv-db-01.prod
        </HoverCardTrigger>
        <HoverCardContent className="flex flex-col gap-3">
          <div className="flex items-center justify-between gap-2">
            <span className="font-medium">srv-db-01.prod</span>
            <Badge variant="soft" tone="success">
              Online
            </Badge>
          </div>
          <dl className="grid grid-cols-[auto_1fr] gap-x-4 gap-y-1">
            <dt className="text-text-secondary">IP address</dt>
            <dd>10.20.4.17</dd>
            <dt className="text-text-secondary">OS</dt>
            <dd>Ubuntu 22.04 LTS</dd>
            <dt className="text-text-secondary">Open alerts</dt>
            <dd>3</dd>
          </dl>
        </HoverCardContent>
      </HoverCard>{" "}
      at 14:02.
    </p>
  )
}
```

## Usage

```tsx
import {
  HoverCard,
  HoverCardContent,
  HoverCardTrigger,
} from "@zenoxai/ui/components/hover-card"
```

```tsx
<HoverCard>
  <HoverCardTrigger href="/assets/srv-db-01">srv-db-01.prod</HoverCardTrigger>
  <HoverCardContent>{/* summary of the asset */}</HoverCardContent>
</HoverCard>
```

A hover card lets the user peek at an asset, a user or a rule mentioned in running text without
following the link. The trigger renders an `<a>`: give it an `href` that leads to the full
record, because the card is only a shortcut to what that page shows.

- To label an icon button or explain a control in a few words, use
  [Tooltip](/components/tooltip).
- For content the user must be able to reach on touch screens or with a keyboard, or that holds
  buttons and fields, use [Popover](/components/popover). A hover card opens on hover and
  keyboard focus only, and its content cannot be tabbed into.

`HoverCardContent` is 16rem wide and opens below the trigger, centered on it. Set `side`, `align` and
`sideOffset` to move it, and `className` to change the width or the layout.

## Examples

### User card

A card for a person: avatar, name, role and a figure that helps decide whether to open the
profile.

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

function HoverCardUser() {
  return (
    <p>
      Assigned to{" "}
      <HoverCard>
        <HoverCardTrigger
          href="#user-msantos"
          className="font-medium text-link underline-offset-4 hover:underline"
        >
          Marina Santos
        </HoverCardTrigger>
        <HoverCardContent side="top" className="flex gap-3">
          <Avatar size="lg">
            <AvatarFallback>MS</AvatarFallback>
          </Avatar>
          <div className="flex flex-col gap-0.5">
            <span className="font-medium">Marina Santos</span>
            <span className="text-text-secondary">
              Tier 2 analyst, Acme Corp
            </span>
            <span className="text-text-muted">12 open investigations</span>
          </div>
        </HoverCardContent>
      </HoverCard>
    </p>
  )
}
```

### Delay

The card opens after the pointer rests on the link for 600ms and closes 300ms after it leaves,
so it does not flash while the pointer crosses the page. Set `delay` and `closeDelay` on the
trigger to change them.

```tsx
import { HoverCard, HoverCardContent, HoverCardTrigger } from "@zenoxai/ui/components/hover-card"

function HoverCardDelay() {
  return (
    <p>
      Detected by{" "}
      <HoverCard>
        <HoverCardTrigger
          href="#rule-impossible-travel"
          delay={200}
          closeDelay={500}
          className="font-medium text-link underline-offset-4 hover:underline"
        >
          Impossible travel
        </HoverCardTrigger>
        <HoverCardContent>
          Two logins from locations more than 1,000 km apart within an hour.
          Enabled in 14 tenants.
        </HoverCardContent>
      </HoverCard>
    </p>
  )
}
```

## Accessibility

- The card is a visual enhancement for pointer and keyboard users. Screen readers announce the
  link only, so the card must never hold the only copy of a piece of information.
- The trigger is a real link. Do not render it as a button or give it an `onClick` that does
  something else than navigate.

## API reference

`import { ... } from "@zenoxai/ui/components/hover-card"`

### HoverCard

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| actionsRef | `RefObject<PreviewCardRootActions \| null>` |  | A ref to imperative actions. - `unmount`: Ends the closing phase of the preview card after an externally controlled closing animation finishes. Call `preventUnmountOnClose()` in `onOpenChange` first, otherwise the preview card completes closing on its own. Whether it leaves the DOM is decided by `keepMounted` on the portal. - `close`: Closes the preview card imperatively when called. |
| defaultOpen | `boolean` | `false` | Whether the preview card is initially open.  To render a controlled preview card, use the `open` prop instead. |
| defaultTriggerId | `string \| null` |  | ID of the trigger that the preview card is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open preview card. |
| handle | `PreviewCardHandle<unknown>` |  | A handle to associate the preview card with a trigger. If specified, allows external triggers to control the card's open state. Can be created with the PreviewCard.createHandle() method. |
| onOpenChange | `((open: boolean, eventDetails: PreviewCardRootChangeEventDetails) => void)` |  | Event handler called when the preview card is opened or closed. |
| onOpenChangeComplete | `((open: boolean) => void)` |  | Event handler called after any animations complete when the preview card is opened or closed. |
| open | `boolean` |  | Whether the preview card is currently open. |
| triggerId | `string \| null` |  | ID of the trigger that the preview card is associated with. This is useful in conjunction with the `open` prop to create a controlled preview card. There's no need to specify this prop when the preview card is uncontrolled (that is, when the `open` prop is not set). |

### HoverCardTrigger

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| closeDelay | `number` | `300` | How long to wait before closing the preview card. Specified in milliseconds. |
| delay | `number` | `600` | How long to wait before the preview card opens. Specified in milliseconds. |
| handle | `PreviewCardHandle<unknown>` |  | A handle to associate the trigger with a preview card. |
| payload | `unknown` |  | A payload to pass to the preview card when it is opened. |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<DetailedHTMLProps<AnchorHTMLAttributes<HTMLAnchorElement>, HTMLAnchorElement>, PreviewCardTriggerState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |

### HoverCardContent

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| align | `"center" \| "start" \| "end"` | `start` | How to align the popup relative to the specified side. |
| alignOffset | `number \| OffsetFunction` | `0` | Additional offset along the alignment axis in pixels. Also accepts a function that returns the offset to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   alignOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.width       : anchor.height;   }} /> ``` |
| render | `ReactElement<unknown, string \| JSXElementConstructor<any>> \| ComponentRenderFn<HTMLProps, PreviewCardPopupState>` |  | Allows you to replace the component's HTML element with a different tag, or compose it with another component.  Accepts a `ReactElement` or a function that returns the element to render. |
| side | `"left" \| "right" \| "top" \| "bottom" \| "inline-end" \| "inline-start"` | `bottom` | Which side of the anchor element to align the popup against. May automatically change to avoid collisions. |
| sideOffset | `number \| OffsetFunction` | `0` | Distance between the anchor and the popup in pixels. Also accepts a function that returns the distance to read the dimensions of the anchor and positioner elements, along with its side and alignment.  The function takes a `data` object parameter with the following properties: - `data.anchor`: the dimensions of the anchor element with properties `width` and `height`. - `data.positioner`: the dimensions of the positioner element with properties `width` and `height`. - `data.side`: which side of the anchor element the positioner is aligned against. - `data.align`: how the positioner is aligned relative to the specified side. @example ```jsx <Positioner   sideOffset={({ side, align, anchor, positioner }) => {     return side === 'top' \|\| side === 'bottom'       ? anchor.height       : anchor.width;   }} /> ``` |

