Hover Card — <mv-hover-card>

Rich preview card on hover or keyboard focus, with open/close delays and an invisible bridge that keeps it open while the pointer travels to it.

CategoryOverlays
TypeWeb Component (<mv-hover-card>)
Statusstable
Also installspopover
Keywordshover-card, preview, profile, mention, popover

When to use

Avoid when

Install

node scripts/add.mjs hover-card --out ./src/marvelous

AI agent with the Marvelous UI MCP server: install_components({ slugs: ["hover-card"], target_dir: "<absolute path>/src/marvelous", framework: "react" }).

Files copied (dependencies included): tokens/tokens.css, core/base.css, core/dom.js, core/element.js, core/focus.js, core/motion.js, core/position.js, components/hover-card/hover-card.js, components/hover-card/hover-card.css, components/popover/popover.js, components/popover/popover.css.

Usage

Canonical markup — start from it and customize with attributes, data-* and CSS variables:

<div style="max-width:30rem;margin:0;text-align:center;font-size:.9375rem;line-height:1.7;color:var(--mv-fg-muted)">
  The design system was started by
  <mv-hover-card placement="bottom" arrow>
    <div data-content>
      <div style="display:flex;gap:.875rem;text-align:left">
        <span aria-hidden="true" style="flex-shrink:0;display:grid;place-items:center;width:2.75rem;height:2.75rem;border-radius:999px;background:var(--mv-accent-subtle);color:var(--mv-accent-fg);font-weight:600;font-size:.875rem">CR</span>
        <div style="display:grid;gap:.25rem;min-width:0">
          <div style="display:flex;align-items:baseline;gap:.375rem;flex-wrap:wrap">
            <strong style="color:var(--mv-fg);font-weight:600">Chloe Ramirez</strong>
            <span style="color:var(--mv-fg-subtle);font-size:.8125rem">@chloe</span>
          </div>
          <p style="margin:0;color:var(--mv-fg-muted);font-size:.8125rem;line-height:1.5">Product designer at Northwork. Obsessed with micro-interactions and 4px grids.</p>
          <div style="display:flex;gap:1rem;margin-top:.375rem;font-size:.75rem;color:var(--mv-fg-subtle)">
            <span><strong style="color:var(--mv-fg);font-weight:600">1,284</strong> followers</span>
            <span><strong style="color:var(--mv-fg);font-weight:600">312</strong> following</span>
          </div>
          <div style="display:flex;align-items:center;gap:.375rem;margin-top:.125rem;font-size:.75rem;color:var(--mv-fg-subtle)">
            <svg viewBox="0 0 24 24" width="13" height="13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg>
            Joined March 2023
          </div>
        </div>
      </div>
    </div>
    <a class="mv-hover-card-trigger" href="#chloe" onclick="event.preventDefault()">@chloe</a></mv-hover-card>
  and its source code lives in
  <mv-hover-card placement="top" open-delay="300">
    <div data-content style="--mv-hover-card-width:19rem">
      <div style="display:grid;gap:.5rem;text-align:left">
        <div style="display:flex;align-items:center;gap:.5rem;color:var(--mv-fg)">
          <svg viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true" style="color:var(--mv-fg-muted)"><path d="M4 19.5v-15A2.5 2.5 0 0 1 6.5 2H20v20H6.5a2.5 2.5 0 0 1 0-5H20"/></svg>
          <strong style="font-weight:600">northwork/marvelous</strong>
          <span style="margin-left:auto;padding:0 .4rem;border:1px solid var(--mv-border);border-radius:999px;font-size:.6875rem;color:var(--mv-fg-muted)">Public</span>
        </div>
        <p style="margin:0;color:var(--mv-fg-muted);font-size:.8125rem;line-height:1.5">Native Web Components, layered CSS and zero dependencies.</p>
        <div style="display:flex;align-items:center;gap:1rem;font-size:.75rem;color:var(--mv-fg-subtle)">
          <span style="display:inline-flex;align-items:center;gap:.35rem"><span aria-hidden="true" style="width:.625rem;height:.625rem;border-radius:999px;background:var(--mv-warning)"></span>JavaScript</span>
          <span>★ 2.4k</span>
          <span>Updated 2 hours ago</span>
        </div>
      </div>
    </div>
    <a class="mv-hover-card-trigger" href="#repo" onclick="event.preventDefault()">northwork/marvelous</a></mv-hover-card>.
</div>

API

Attributes

NameTypeDefaultDescription
placementtop | bottom | left | right[-start|-end]bottomPreferred side, flipped when there isn’t enough room.
offsetnumber8Distance from the trigger (px).
open-delaynumber500Delay before opening (ms).
close-delaynumber300Grace delay before closing (ms).
arrowbooleanShows an arrow.
openbooleanOpens/closes programmatically.
disabledbooleanDisables the card.

Properties

NameTypeDescription
isOpenbooleanRead-only.

Events

NameDescription
mv-openAfter opening.
mv-closeAfter closing.

Content structure

NameDescription
first childTrigger, ideally a link (<a>) that makes sense on its own.
[data-content]Card content (uses the .mv-popover style).

CSS classes

NameDescription
mv-hover-card-triggerDotted-underline mention style for the trigger.

CSS variables

NameDefaultDescription
--mv-hover-card-width20remCard width.
--mv-popover-*Background, radius and padding inherited from Popover.

Accessibility

Visual enhancement: the trigger must make sense on its own. Opens on mouse hover and keyboard focus (:focus-visible), never on touch; Tab moves into the card (which stays open while focus is inside), Escape closes it. The content isn’t announced automatically: don’t put essential information in it.