Morphos
Overlays

Preview Card

A floating card that appears on hover to provide a rich preview of linked or referenced content.

Interactive example

Installation

npm install @morphos/overlays
pnpm add @morphos/overlays
yarn add @morphos/overlays
bun add @morphos/overlays

Import

import { PreviewCard, PreviewCardTrigger, PreviewCardContent } from '@morphos/overlays'

Usage

@Component()
class MyComponent extends StatefulComponent {
  @State() previewCard = new PreviewCard({ openDelay: 300, closeDelay: 100 })

  render() {
    return (
      <>
        <PreviewCardTrigger card={this.previewCard}>
          @morphos_ui
        </PreviewCardTrigger>
        <PreviewCardContent card={this.previewCard}>
          <img src="/avatar.png" alt="Morphos UI" />
          <strong>Morphos UI</strong>
          <p>Headless PraxisJS component library.</p>
        </PreviewCardContent>
      </>
    )
  }
}

Compound components

ComponentDescription
PreviewCardRoot state manager. Owns open state, hover delay timers, and the computed anchor position.
PreviewCardTrigger<span> that opens the card (after openDelay) on mouseenter/focus, and schedules closing (after closeDelay) on mouseleave/blur.
PreviewCardContentRenders into a Portal, positioned with position: fixed. Sets role="tooltip" and data-open. Re-arms the open/close timers on its own mouseenter/mouseleave, so moving the pointer from the trigger into the card keeps it open.

Props — PreviewCard

PropTypeDefaultDescription
openbooleanControlled open state. When set, the consumer owns the state.
defaultOpenbooleanInitial open state in uncontrolled mode (no default value is assigned; treated as false when unset).
onOpenChange(open: boolean) => voidCalled when the open state changes.
openDelaynumber300Milliseconds to wait before opening.
closeDelaynumber100Milliseconds to wait before closing.
side"top" | "bottom" | "left" | "right""bottom"Which edge of the trigger the card is placed against.
align"start" | "center" | "end""start"Alignment of the card along the trigger's perpendicular axis.
sideOffsetnumber4Gap in pixels between the trigger and the card.
childrenChildrenContent — typically PreviewCardTrigger and PreviewCardContent.

Methods

MethodDescription
openWithDelay()Cancels any pending close, then opens the card after openDelay ms.
closeWithDelay()Cancels any pending open, then closes the card after closeDelay ms.
openCard()Opens the card immediately (recomputing its position). Emits onOpenChange(true).
closeCard()Closes the card immediately. Emits onOpenChange(false).

Props — PreviewCardTrigger

PropTypeDefaultDescription
cardPreviewCardThe PreviewCard instance this trigger controls.
childrenChildrenThe trigger element content.
classstringCSS class.
idstringHTML id.

Props — PreviewCardContent

PropTypeDefaultDescription
cardPreviewCardThe PreviewCard instance this content belongs to.
childrenChildrenPreview card content.
classstringCSS class.
idstringHTML id. Falls back to an auto-generated id.

data-* attributes

AttributeElementWhen present
data-openPreviewCardContent rootCard is visible

Unlike Tooltip, PreviewCardTrigger does not set a data-open attribute of its own — only PreviewCardContent reflects data-open. PreviewCardTrigger does set aria-describedby, pointing at the content's id.

PreviewCardContent renders inside a Portal. Moving the pointer from the trigger into the content area does not close the card — the closeDelay gives the user time to hover over the card before it dismisses. Its position is computed with computeAnchorPosition() from @morphos/core, using PreviewCardTrigger's bounding rect and the side/align/sideOffset props on PreviewCard. PreviewCard does not trap focus or lock scroll — it is non-modal.

Styling example

.morphos-preview-card-content {
  z-index: 100;
  width: 20rem;
  padding: var(--morphos-space-4);
  background: var(--morphos-color-bg);
  border: 1px solid var(--morphos-color-border);
  border-radius: var(--morphos-radius-lg);
}

On this page