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
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)
Placement
12 directions: top / bottom / left / right × start / center / end.
12 directions
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)
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)
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)
Dual-axis offset
offset main-axis distance (gap between popup and trigger), skidding cross-axis shift.
Dual-axis offset (offset / skidding)
Width
width as a number (px) or trigger / target (same width as the trigger).
Width (width)
Append-to container
append-to: mounts the card into a portal inside the specified container (the DOM belongs to that container) while the card keeps position: fixed viewport coordinates with no translation — handy for escaping clipping contexts such as overflow: hidden.
append-to container
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
Scroll follow & stickiness
Scrolling inside a scroll container repositions the card by default (sticky=partial); once the anchor leaves the viewport it hides per hide-when-detached (or clamps to the viewport edge when not enabled). sticky="always" pins the card to the viewport edge once the anchor scrolls out (stays visible). sticky="off" explicitly disables scroll repositioning.
sticky three modes (inside a scroll container)
Custom collision boundary
collision-boundary: flips and clamps against the specified element's rect instead of the viewport (first match in multi-ancestor scenes); the collisionBoundary property accepts an element directly.
collision-boundary (boundary container)
Disabled
disabled: hover/focus no longer opens the popup (the controlled open attribute still works).
Disabled (disabled)
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)
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)
Tap to toggle on touch
Hover is unreliable on touch devices (pointer: coarse): the hover card automatically degrades to tap to toggle — tap the trigger to open, tap again to close, or tap anywhere outside the card and the trigger to close. Desktop hover behavior is unchanged.
Tap to toggle (automatic on coarse pointers)
API
oas-hover-card
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
append-to | Mount point (portal): body or a CSS selector. When open and set, the card moves into an isolated shadow inside the target container (styles stay scoped) while keeping position: fixed viewport coordinates — no coordinate translation — escaping clipping contexts such as overflow: hidden / transform; when unset the card stays in the component's own shadow | string | — |
arrow | Whether to show the arrow, default true; arrow="false" hides it (the arrow element and ::part(arrow) remain) | string | true |
arrow-merge | Corner-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 placements | boolean | — |
arrow-point-at-center | Point the arrow at the trigger center (keeps pointing at the anchor after viewport clamping); by default the arrow stays at the panel center | boolean | — |
auto-adjust-overflow | Auto-adjust at viewport edges (flip/clamp), default true; "false" disables it and positions strictly per the declared placement (the popup may overflow the viewport) | string | true |
close-delay | Close delay in ms, separate from open-delay; falls back to the delay alias, then to 150 | — | — |
collision-boundary | Custom collision boundary (selector string, first match in multi-ancestor scenes; the collisionBoundary property accepts an element directly): flips and clamps against that element's rect instead of the viewport | Element | null | — |
collision-padding | Viewport clamping padding in px, default 4 | — | — |
content | Content text | string | — |
delay | Show/hide delay in ms, legacy alias: applies to both open and close when open-delay/close-delay are unset; individual values win when set | — | — |
disabled | Disable the popup: hover/focus triggers no longer open it; the controlled open attribute still works | boolean | — |
fallback-placements | Custom 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 | — | — |
group | Delay 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-detached | Hide the card when the anchor is fully scrolled out of the viewport; keeps the open state and restores automatically when scrolled back | boolean | — |
offset | Main-axis distance in px (gap between popup and trigger), default 8 | — | — |
open | Controlled display (boolean attribute; shows when present) | boolean | — |
open-delay | Open delay in ms, separate from close-delay; falls back to the delay alias, then to 300 | — | — |
placement | Popup placement, 12 directions: top/bottom/left/right × start/center/end (e.g. bottom-start) | string | top |
skidding | Cross-axis offset in px, shifts along the axis perpendicular to the main axis | — | — |
sticky | Scroll stickiness: partial (default) repositions with the anchor on scroll and hides per hide-when-detached once the anchor leaves the viewport (or clamps to the viewport edge when not enabled); always pins the card to the viewport edge once the anchor scrolls out (stays visible); off disables scroll repositioning | string | partial |
title | Title text (rendered into the visible title region; absorbed from the host on read so no native hover tooltip remains; pass an empty string to clear); use slot="title" for rich content | string | — |
width | Width customization: number (px) or trigger/target (same width as the trigger); falls back to CSS min-width | — | — |
Events
| Event | Description |
|---|---|
oas-open-change | Dispatched when the open state changes, detail: { open } |
Slots
| Name | Description |
|---|---|
| default | Trigger (first non-slot="content" child), triggered on hover/focus |
content | Rich content slot: free-form HTML preview inside the card (links/buttons etc., interactive) |
title | Rich title content slot, overrides the title attribute text when present |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-glass-blur | none |
--oas-glass-ring | transparent |
--oas-hover-card-arrow-height | 12px |
--oas-hover-card-arrow-radius | 0 |
--oas-hover-card-arrow-width | 12px |