Hover Card
Headless hover-and-focus preview primitives with delayed disclosure and floating positioning.
Hover Card in motion
When to Use
Use HoverCard for supplemental, nonessential preview content such as a short profile summary. Use Tooltip for a brief label, Popover for content with buttons or other interaction, and Dialog for a task that must hold focus. HoverCard closes when focus leaves and does not create a dialog or popover accessibility relationship, so never put required actions inside it.
Features
The behavior Atom owns before your product adds appearance.
- Supports controlled and uncontrolled open state.
- Opens from mouse-capable pointer hover and focus-visible Trigger interaction; touch input and its browser-generated compatibility events do not open the preview or replace the Trigger's native action.
- Does not install hover disclosure on touch-only devices and updates that capability when the browser's available input devices change.
- Uses configurable open and close delays and a safe pointer corridor that keeps Content open while the pointer crosses the gap from Trigger to Content.
- Positions centered Content by shifting within the viewport before considering placement fallbacks. Edge-aligned Content resolves alternate alignments before shifting, and both modes retain opposite- and perpendicular-side fallbacks; Arrow coordinates follow the resolved result.
- Supports inline or custom-container portals.
- Participates in topmost-layer Escape dismissal.
Import
Anatomy
API Reference
Root
Owns delayed open state and renders no wrapper.
| Prop | Type | Default |
|---|---|---|
open | boolean | - |
defaultOpen | boolean | false |
onOpenChange | (open: boolean) => void | - |
openDelay | number | 700 |
closeDelay | number | 300 |
disabled | boolean | false |
Trigger
Provides the positioning reference and mouse-capable hover/focus events. It
renders a focusable span by default. With asChild, the child keeps its own
tab order and native touch behavior.
| Prop | Type | Default |
|---|---|---|
asChild | boolean | false |
render | RenderProp | - |
| Data attribute | Values |
|---|---|
[data-slot] | "hover-card-trigger" |
[data-state] | "open" | "closed" |
Trigger emits no aria-expanded, aria-controls, or dialog/popover role.
Disabled Root prevents opening and removes the default Trigger from the Tab
order, but Trigger emits no disabled ARIA or data attribute.
Portal
Moves Content to document.body by default without a wrapper.
| Prop | Type | Default |
|---|---|---|
container | Element | DocumentFragment | null | document.body |
disabled | boolean | false |
Content
Renders a positioned generic div. It has no owned landmark or popup role;
ariaLabel is passed as aria-label but does not create a Trigger relationship.
Content exposes measured --atom-floating-available-width and
--atom-floating-available-height properties.
Portalled Content preserves an explicit dir; otherwise it resolves direction
from Trigger and then Direction.Provider.
| Prop | Type | Default |
|---|---|---|
side | "top" | "right" | "bottom" | "left" | "bottom" |
align | "start" | "center" | "end" | "center" |
sideOffset | number | 8 |
ariaLabel | string | - |
| ARIA attribute | Values |
|---|---|
aria-label | Value from ariaLabel |
| Data attribute | Values |
|---|---|
[data-slot] | "hover-card-content" |
[data-state] | "open" | "closed" |
[data-side] | Resolved side after collision handling |
[data-positioned] | Present after positioning |
Arrow
Renders a decorative SVG aligned to Content's resolved side. Custom children replace its default polygon.
| Prop | Type | Default |
|---|---|---|
width | number | 10 |
height | number | 5 |
children | ReactNode | Default polygon |
asChild | boolean | false |
render | RenderProp | - |
| ARIA attribute | Values |
|---|---|
aria-hidden | "true" |
| Data attribute | Values |
|---|---|
[data-slot] | "hover-card-arrow" |
[data-side] | Resolved Content side |
getHoverCardArrowGeometry
Returns SVG dimensions, outward size, and polygon points for a side, width, and height. This is useful when building a compatible custom Arrow.
The entry point also exports useHoverCardContext and
useHoverCardContentContext for advanced custom parts. Both throw outside
their required Root or Content provider.
Examples
Profile Preview
Accessibility
HoverCard has no standalone WAI-ARIA popup pattern. Trigger remains the semantic element supplied by the consumer, Content is supplemental document content, and Arrow is hidden from assistive technology. The preview must not be the only place important information or actions are available. Touch does not open HoverCard, so a Trigger link keeps its normal tap and long-press behavior.
| Key | Description |
|---|---|
Tab / Shift+Tab | Focus-visible entry can open Trigger; leaving closes after closeDelay. |
Escape | Closes the topmost open HoverCard immediately. |
Changelog
Unreleased
0.24.0
- Added public Agent Knowledge for component selection, required composition, recurring mistakes, and validation.
- Preserved centered Content alignment near viewport edges by shifting it into view before considering alternate placements.
0.6.9
- Preserved resolved Trigger or provider direction on portalled Content while
retaining explicit Content
dirprecedence.
0.6.8
- Exposed measured available dimensions through headless floating properties for constrained styled surfaces.
0.6.6
- Disabled hover interaction when the browser reports no hover-capable input and captured touch pointer entry before native compatibility mouse events on hybrid devices.
0.6.5
- Added a short post-touch compatibility-event guard so intermittent Safari mouse and focus synthesis cannot open HoverCard after touch activation.
0.6.4
- Limited hover disclosure to mouse-capable pointers so touch keeps the Trigger's native tap and long-press behavior.
- Added a safe geometric corridor from Trigger to Content and prevented exit-retained Content from reopening itself during its closing motion.
0.6.3
- Prioritized every usable alignment on the requested side, followed by the opposite side, before allowing perpendicular-axis collision fallbacks.
0.6.2
- Added perpendicular-side collision fallbacks after the preferred and opposite sides, preventing wide previews from remaining cropped on a constrained axis.
0.3.1
- Fixed exit-presence cleanup so closed HoverCard Content unmounts after its CSS motion window even when no end event is emitted.
0.2.0
- Fixed HoverCard render/default trigger positioning by updating Floating UI after the trigger ref commits.
- Made default and
renderHoverCard triggers keyboard focusable while keeping opening scoped to hover and focus-visible interactions. - Added shared dismissable layer Escape handling so HoverCard participates in topmost-layer dismissal with other overlays.
0.1.0
- Initial Atom release.