Skip to content

HoverCard

A hover/focus-triggered preview card whose popup stays open on hover (no flicker). Rich content slot, 12-way placement, separate open/close delays, arrow (incl. corner-merge), dual-axis offset, collision tuning, append-to container, delay groups and controlled display.

Basic usage

Hover or focus the trigger to show the preview card.

Trigger on hover

Hover to view

Rich content slot

The slot="content" slot accepts any HTML preview (links / buttons / images…). The popup stays open on hover: moving the pointer from the trigger into the card keeps it open, so links and buttons inside stay interactive (the hover area = trigger + popup panel).

Rich preview (hoverable popup)

Hover to view user
O
Ouyang Xiaoyu
Frontend Engineer · Hangzhou
Into open source and Web Components — code and writing.
MessageProfile

Placement

12 directions: top / bottom / left / right × start / center / end.

12 directions

top-starttoptop-endbottom-startbottombottom-endleft-startleftleft-endright-startrightright-end

Show / hide delay

open-delay / close-delay are configured separately: appears about 800ms after hover, closes 300ms after leaving. delay is a legacy alias (applies to both when the individual ones are unset).

Separate delays (open-delay / close-delay)

Separate delaysdelay alias

Arrow

The arrow is shown by default; arrow="false" hides it; arrow-point-at-center keeps the arrow pointing at the trigger center.

Arrow (default / hidden / pointing at center)

Default arrowHidden arrowPoint at center

Corner-merged arrow

arrow-merge: for *-start / *-end placements the arrow fuses with the panel corner into a right-angle triangle.

Corner-merged arrow (arrow-merge)

bottom-startbottom-end

Dual-axis offset

offset main-axis distance (gap between popup and trigger), skidding cross-axis shift.

Dual-axis offset (offset / skidding)

offset=20skidding=24

Width

width as a number (px) or trigger / target (same width as the trigger).

Width (width)

width=320width=trigger

Append-to container

append-to: the card is absolutely positioned inside the specified container (the container is promoted to a positioning context) — handy for custom panels / overlay regions.

append-to container

Hover to view

Collision tuning

collision-padding viewport clamping padding; fallback-placements custom fallback sequence; hide-when-detached hides the card when the anchor is scrolled out of view; auto-adjust-overflow="false" disables auto adjustment.

Collision tuning

Collision paddingFallbackHide detachedNo adjust

Disabled

disabled: hover/focus no longer opens the popup (the controlled open attribute still works).

Disabled (disabled)

Hover does nothing

Delay group

Triggers sharing the same group value share delays: moving the pointer between members skips the open-delay (opens immediately) and closes the previous one immediately.

Delay group (group)

User AUser BUser C

Controlled display & events

The open attribute controls visibility; visibility changes dispatch oas-open-change (detail: { open }). Hover/focus triggers still apply in addition.

Controlled display (open + oas-open-change)

ShowHideopen: falseTrigger element

API

Attributes

AttributeDescriptionTypeDefault
append-toPositioning container selector (e.g. #panel): the card is absolutely positioned inside that container (container is promoted to a relative positioning context), coordinates translated accordingly; defaults to position: fixed viewport coordinatesstring
arrowWhether to show the arrow, default true; arrow="false" hides it (the arrow element and ::part(arrow) remain)stringtrue
arrow-mergeCorner-merged arrow mode: for -start/-end placements a right triangle merges flush with the panel corner — legs collinear with the panel edges (their strokes continue the panel border band), tip pointing orthogonally toward the anchor; the matching corner radius is zeroed; no effect for centered placementsboolean
arrow-point-at-centerPoint the arrow at the trigger center (keeps pointing at the anchor after viewport clamping); by default the arrow stays at the panel centerboolean
auto-adjust-overflowAuto-adjust at viewport edges (flip/clamp), default true; "false" disables it and positions strictly per the declared placement (the popup may overflow the viewport)stringtrue
close-delayClose delay in ms, separate from open-delay; falls back to the delay alias, then to 150
collision-paddingViewport clamping padding in px, default 4
contentContent textstring
delayShow/hide delay in ms, legacy alias: applies to both open and close when open-delay/close-delay are unset; individual values win when set
disabledDisable the popup: hover/focus triggers no longer open it; the controlled open attribute still worksboolean
fallback-placementsCustom fallback sequence (comma-separated bases, e.g. left,top): tried in order when the requested placement lacks space; defaults to flipping to the opposite side
groupDelay group name: components sharing the same group value share delays — moving between members skips the open-delay (opens immediately) and closes the previous one immediately
hide-when-detachedHide the card when the anchor is fully scrolled out of the viewport; keeps the open state and restores automatically when scrolled backboolean
offsetMain-axis distance in px (gap between popup and trigger), default 8
openControlled display (boolean attribute; shows when present)boolean
open-delayOpen delay in ms, separate from close-delay; falls back to the delay alias, then to 300
placementPopup placement, 12 directions: top/bottom/left/right × start/center/end (e.g. bottom-start)stringtop
skiddingCross-axis offset in px, shifts along the axis perpendicular to the main axis
titleTitle textstring
widthWidth customization: number (px) or trigger/target (same width as the trigger); falls back to CSS min-width

Events

EventDescription
oas-open-changeDispatched when the open state changes, detail: { open }

Slots

NameDescription
defaultTrigger (first non-slot="content" child), triggered on hover/focus
contentRich content slot: free-form HTML preview inside the card (links/buttons etc., interactive)

Released under the MIT OR Apache-2.0 License.