Hover Card

Components

Hover Card New · experimental

shadcn's Hover Card with goo. The card blooms out of the edge facing its link, splashes, and shrinks back into it.

Hover the link (or focus it with the keyboard).

Customize

Preset
Speed 1.00×
Bloom from
Surface
Open slosh 1.00×
Open drips 1.00×
Close slosh 1.00×

GoopHoverCard wraps the same reka-ui Hover Card primitive as shadcn-vue's HoverCard, with the same API. Open and close delays, keyboard focus, touch handling, and positioning work the same. Swap the imports and you're done.

Installation

Nuxt

pnpm add @goopui/nuxt
nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@goopui/nuxt'],
})

The module auto-imports every GoopHoverCard* part, adds goop.css, and points Tailwind at the component classes. It needs Tailwind CSS v4 and the shadcn tokens (--popover, --popover-foreground, --radius).

Vue

pnpm add @goopui/vue
main.css
@import "tailwindcss";
@import "@goopui/vue/goop.css";

Usage

<script setup lang="ts">
// Nuxt auto-imports these. In plain Vue, import them:
import { GoopHoverCard, GoopHoverCardContent, GoopHoverCardTrigger } from '@goopui/vue'
</script>

<template>
  <GoopHoverCard :open-delay="200">
    <GoopHoverCardTrigger href="https://nuxt.com" class="underline underline-offset-4">
      @nuxt
    </GoopHoverCardTrigger>
    <GoopHoverCardContent>
      <p class="text-sm font-semibold">@nuxt</p>
      <p class="text-sm">The intuitive Vue framework.</p>
    </GoopHoverCardContent>
  </GoopHoverCard>
</template>

The parts are GoopHoverCard, GoopHoverCardTrigger, and GoopHoverCardContent. All the goo lives on GoopHoverCardContent.

Behavior

  • Bloom from the trigger. The card pools from a droplet on its edge facing the link, spreads out with a lobed edge, overshoots, and wobbles to rest (wobble, openSlosh). Then it splashes a few drops all around, kept off the link (openDrips).
  • Close. The card pulls in, wobbles, and shrinks back into the edge it grew from (closeSlosh).
  • Content stays sharp. The card's background, ring, and shadow are drawn on an aria-hidden surface behind the content, so the text is never filtered. The content fades in once the goo settles (fade).

Bloom origin

bloomFrom picks where the bloom starts: 'trigger' (the default, the card's edge facing its link) or 'center' (the card's own center, like Popover).

<GoopHoverCardContent>...</GoopHoverCardContent>                     <!-- from the edge facing the link -->
<GoopHoverCardContent bloom-from="center">...</GoopHoverCardContent> <!-- from its center -->

Surface color

A hover card's trigger is usually a link with no background, so the card defaults to surface="popover": shadcn's popover tokens. 'trigger' takes the trigger's colors, and any CSS color works too.

Turning parts off

Every effect is its own toggle, and they all default to on:

<GoopHoverCardContent :open-drips="false">...</GoopHoverCardContent>  <!-- no splash -->
<GoopHoverCardContent :wobble="false">...</GoopHoverCardContent>      <!-- no overshoot -->
<GoopHoverCardContent :close-slosh="false">...</GoopHoverCardContent> <!-- a plain shrink on close -->

:goo="false" renders exactly shadcn's HoverCardContent, with its own enter and exit animation.

Driving it from code

GoopHoverCardContent exposes its engine handle as handle (null before it mounts, or when goo is off). The card only exists while open.

Props

The root and trigger take shadcn-vue's props (openDelay, closeDelay, asChild, ...). GoopHoverCardContent takes reka-ui's HoverCardContent props (side, align, sideOffset, and the rest), class, and these goo props. Defaults are align="center" and sideOffset 4.

GoopHoverCardContent goo props
PropTypeDefaultNotes
goobooleantrueMaster switch. false renders a plain shadcn HoverCardContent.
flowbooleantrueThe card opens in flowStyle. false: it inflates from a bulb at the trigger edge.
flowStyle'bloom' | 'neck''bloom''bloom' pools from a point and spreads with a lobed edge, overshoots, then splashes. 'neck' runs out of the trigger through a thick neck.
bloomStart'single' | 'merge''single''single': one droplet swells. 'merge': a few drops fuse.
bloomFrom'trigger' | 'center''trigger'Where the bloom starts. 'trigger': the card's edge facing its trigger. 'center': the card's own center, like Popover. Close shrinks back to the same spot.
bridgebooleantrueThe bulb and lumpy neck between the trigger and the card. Not used by bloom.
wobblebooleantrueThe open overshoot and settle.
momentumbooleantrueThe launch away from the trigger. Not used by bloom.
fadebooleantrueThe content fades in once the goo settles.
openSloshboolean | numbertrueOn open, every edge bulges past rest, rebounds, and wobbles. A number from 0 to 2 sets the strength.
openDripsboolean | numbertrueOn open, drops splash off all around, kept off the trigger. A number from 0 to 2 sets the strength.
openDripAmountnumber1Splash drop count, 0 to 3.
openDripSizenumber1Splash drop size, 0.3 to 2.5.
openDripFlingnumber1How far the drops are flung, 0 to 3.
openDripVarietynumber0.7Mix of globs and specks, 0 to 1.
sloshVarietynumber1How differently each side bulges, 0 to 1. 0 is an even, centred bulge.
closeSloshboolean | numbertrueOn close, the card pulls in and wobbles before it shrinks back.
surface'popover' | 'trigger' | string'popover'The card's color. 'popover' uses shadcn's popover tokens. 'trigger' takes the trigger's colors. Any CSS color works.
speednumber1Animation speed multiplier.
preset'subtle' | 'playful' | 'wild'app config, then playfulThe overall feel.
renderer'svg' | 'canvas''svg'How the goo is drawn.

Accessibility

Focus handling and dismissal come from reka-ui; like shadcn's, a hover card is for sighted mouse and keyboard users and its content shouldn't be the only way to reach information. The goo surface is aria-hidden and can't be clicked, and the content is never filtered. Under reduced motion the card opens and closes plainly: it keeps its goo shape and color, but the bloom, slosh, and splash are off. See Accessibility & reduced motion.