Manual UI Templates HoverCard

HoverCard

elements man ui/templates/hover-card

A preview of what a link points to, shown while the pointer rests on it.

Example
import { HoverCard, HoverCardTrigger } from "@elements/ui/hover-card"; <HoverCard> <a slot="trigger" href="/u/ada">@ada</a> <div class="hover-card-media"> <img src={user.avatar} alt="" width="40" height="40"> <div> <strong>Ada Lovelace</strong> <p>Wrote the first program.</p> </div> </div> </HoverCard>

Parts

Part What it is
HoverCard The root: owns open, renders the trigger slot and, while open, the floating card.
.hover-card-media A class for the usual layout: an avatar or image, then a column of text.
HoverCardTrigger Wraps a link anywhere on the page for the HoverCard with the same handle. Takes handle and payload.

Attributes

HoverCard

Attribute Type Default Description
open boolean (two-way) false Whether the card is open. Bind it to control it; the card writes false back when it closes itself.
openDelay number 700 ms the pointer (or focus) rests on the trigger before the card opens. 0 opens at once.
closeDelay number 300 ms after the pointer leaves the trigger and card before it closes.
side "top" | "right" | "bottom" | "left" | "inline-start" | "inline-end" "bottom" Preferred side of the trigger; it flips when there is no room. inline-start and inline-end follow the text direction (right and left under dir=rtl).
align "start" | "center" | "end" "center" Alignment along that side.
sideOffset number | ((d: OffsetData) => number) 4 Gap from the trigger, in px.
alignOffset number | ((d: OffsetData) => number) 0 Shift along the alignment axis, in px.
avoidCollisions boolean true Flip and shift to stay on screen.
collisionAvoidance { side?: "flip" | "shift" | "none"; align?: "flip" | "shift" | "none"; fallbackAxisSide?: "start" | "end" | "none" } | null null How it stays in view. side "none" keeps the side with no flip, "shift" keeps the side and slides it over the trigger into view; align "flip" tries the other alignment before sliding, "shift" only slides, "none" neither; fallbackAxisSide "start" tries the inline start side of the other axis first, "end" (the default) the end side, "none" never moves it to the other axis. avoidCollisions={false} turns all of it off.
positionMethod "fixed" | "absolute" "fixed" "absolute" places the card in page coordinates instead of viewport ones.
collisionPadding number 8 Distance kept from the viewport edge, in px.
collisionBoundary string | Element | Element[] "" A selector or elements whose edges flip and shift keep it inside, besides the viewport.
arrowPadding number 6 Distance the arrow keeps from the corners, in px.
sticky "partial" | "always" "partial" "always" keeps it in the collision boundary after its anchor scrolls away.
hideWhenDetached boolean false Hide the card while the trigger is scrolled out of view.
anchor string "" CSS selector of an element to position against instead of the trigger.
keepMounted boolean false Keep the closed card in the page, hidden, rather than removing it.
disableAnchorTracking boolean false Place it once when it opens; it stays put while the page scrolls, and is placed again on a window resize.
handle string "" Names it for HoverCardTrigger parts elsewhere on the page.
triggerId string (two-way) "" The id of the active trigger's element. Set it with open to open against that trigger.
payload string (two-way) "" The payload of the HoverCardTrigger it is showing for, for the content to read.
backdrop boolean false Dim the page under the open card. The pointer passes through it.
arrow boolean false Draw an arrow pointing at the trigger.
size "auto" | "sm" | "md" | "lg" "md" Card width. auto fits the content.
class string "" Extra classes on the card.
onOpenChange (open: boolean, details: OpenChangeDetails) => void () => {} Called when the card opens or closes itself, before the change. details.reason says why (trigger-press, trigger-hover, escape-key, outside-press, close-press, focus-out); details.trigger is the trigger element that caused it (undefined when no trigger did); details.cancel() keeps the current state. Not called for changes the caller makes.
onOpenChangeComplete (open: boolean) => void () => {} Called after the enter or exit animation finishes.
onEscapeKeyDown (e: KeyboardEvent) => void () => {} Called on Escape; e.preventDefault() keeps it open.
onPointerDownOutside (e: PointerEvent) => void () => {} Called on a press outside; e.preventDefault() keeps it open.

HoverCardTrigger

Attribute Type Default Description
handle string (required) The handle it is a trigger for.
payload string "" Data handed to payload while this trigger is active.

Slots

Slot Content
trigger The element the pointer rests on, usually a link. It keeps its own role and gets data-state.
default The card's content.

Keyboard

Keys Action
Tab Focusing the trigger opens the card after openDelay; Tab again moves into links in the card, and leaving both closes it.
Enter Follows the trigger link.
Escape Closes the card.

Data attributes

Attribute Values On Description
data-state "open" | "closed" trigger, .hover-card closed during the exit animation.
data-side "top" | "right" | "bottom" | "left" .hover-card, .popover-arrow The side it ended up on.
data-align "start" | "center" | "end" .hover-card
--transform-origin position .hover-card The anchor-facing edge; the enter animation scales from it.
--anchor-width, --anchor-height px .hover-card The trigger's size.
--available-width, --available-height px .hover-card Room to the viewport edge; a tall card scrolls inside it.
--popover-arrow-size length .hover-card Set on the card's class to size the arrow.
data-popup-open present trigger While open; the same moment as the trigger's open data-state.
data-open / data-closed present .hover-card, .popover-arrow The open state as two flags; data-closed during the exit animation.
data-align "start" | "center" | "end" .popover-arrow The alignment it ended up with.
data-uncentered present .popover-arrow When the arrow cannot point at the trigger's middle (held off a corner).
data-anchor-hidden present .hover-card With hideWhenDetached: while the trigger is scrolled out of view.
data-starting-style / data-ending-style present .hover-card On the first frame of the enter animation, and through the exit animation.
--positioner-width / --positioner-height px .hover-card The card positions itself, so these are its own size while open.

Accessibility

  • A hover card is for sighted pointer users: it adds no role and nothing a screen reader must hear. The trigger keeps its meaning as a link.
  • Keyboard focus on the trigger opens it too, and its links can be reached with Tab while it is open.
  • Opening never moves focus. Touch does not open it; a tap follows the link.

See also