macbetter

Presentation

Hover Card

Preview where a link goes when the pointer rests on it.

The release notes are on the macbetter site, with a page for every component.
import { HoverCard, HoverCardContent, HoverCardTrigger } from "macbetter/hover-card"

export default function Example() {
  return (
    <div style={{ maxWidth: 420, lineHeight: 1.5 }}>
      The release notes are on the{" "}
      <HoverCard>
        <HoverCardTrigger href="https://macbetter.dev/docs/introduction">macbetter site</HoverCardTrigger>
        <HoverCardContent>
          <div
            aria-hidden="true"
            style={{
              height: 132,
              borderRadius: "inherit",
              borderEndStartRadius: 0,
              borderEndEndRadius: 0,
              background:
                "radial-gradient(120% 120% at 0% 0%, var(--mb-accent), transparent 60%), radial-gradient(120% 120% at 100% 100%, var(--mb-accent-secondary), transparent 60%), var(--mb-bg-secondary)",
            }}
          />
          <div style={{ display: "grid", gap: 2, padding: "10px 14px 12px" }}>
            <strong style={{ font: "var(--mb-text-headline)" }}>macbetter — macOS, iPadOS and iOS for the web</strong>
            <span style={{ color: "var(--mb-label-secondary)", font: "var(--mb-text-callout)" }}>
              macbetter.dev
            </span>
          </div>
        </HoverCardContent>
      </HoverCard>
      , with a page for every component.
    </div>
  )
}

When to use it

Use a hover card for a link preview: a page, a person’s profile, a document. It only appears for someone who pauses on the link, so everything in it must also be on the page the link goes to. For a hint on a button, use a Tooltip; for content that opens on a press, a Popover.

Usage

import { HoverCard, HoverCardContent, HoverCardTrigger } from "macbetter/hover-card"

HoverCardTrigger is a real link: give it an href, and pressing it navigates. The card waits 600ms before it opens and stays 300ms after the pointer leaves, so the pointer can cross onto it. Media placed first in the card takes the card’s top corners.

For a feed with many links, connect them all to one card with createHoverCardController() and a payload per link.

Platform behavior

  • macOS and iPadOS with a pointer. Thick material with 16pt (macOS) or 22pt (iPadOS) corners, growing out of the link on a quick spring. No arrow by default, like Safari’s link previews; pass arrow to add one.
  • Touch. There’s no hover: a tap follows the link. People can still reach the card’s content on the destination page.

Accessibility

  • The trigger stays a link with its own name; the card is a preview, not a dialog.
  • Keyboard focus resting on the link opens the card, Tab moves into it when it has links of its own, and Escape closes it.

API

HoverCard

Takes every ui-sdk Hover Card root prop.

PropTypeDefaultDescription
delaynumber600Milliseconds the pointer or focus rests before it opens.
closeDelaynumber300Milliseconds it stays after the pointer leaves.
disabledbooleanfalseLeaves a plain link.

HoverCardContent

PropTypeDefaultDescription
arrowbooleanfalseDraws an arrow that points at the link.
side"top" | "right" | "bottom" | "left""bottom"The edge of the link it opens on.
sideOffsetnumber8, or 12 with an arrowThe gap to the link.
Data attributeOnMeaning
data-open.mb-hover-card-triggerIts card is showing
data-side.mb-hover-card, .mb-hover-card-arrowWhere it landed
data-starting-style, data-ending-style.mb-hover-cardEntering and leaving