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.
Category Overlays Type Web Component (<mv-hover-card>) Status stable Also installs popover Keywords hover-card, preview, profile, mention, popover
When to use
A user mention or link should preview a profile or page on hover without navigating away Supplementary details help desktop users but aren't needed to complete the task
Avoid when
The content is essential or must work on touch devices, where the card never opens → use Popover instead The hint is a short plain-text label for an icon button → use Tooltip instead
Get Hover Card. Included in every plan: the Pro pack ships all 226 components with the CLI and the MCP server used below.
See plans
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
Name Type Default Description placementtop | bottom | left | right[-start|-end] bottomPreferred side, flipped when there isn’t enough room. offsetnumber 8Distance from the trigger (px). open-delaynumber 500Delay before opening (ms). close-delaynumber 300Grace delay before closing (ms). arrowboolean Shows an arrow. openboolean Opens/closes programmatically. disabledboolean Disables the card.
Properties
Name Type Description isOpenboolean Read-only.
Events
Name Description mv-openAfter opening. mv-closeAfter closing.
Content structure
Name Description first childTrigger, ideally a link (<a>) that makes sense on its own. [data-content]Card content (uses the .mv-popover style).
CSS classes
Name Description mv-hover-card-triggerDotted-underline mention style for the trigger.
CSS variables
Name Default Description --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.