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.
Customize
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
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
@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-hiddensurface 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.
| Prop | Type | Default | Notes |
|---|---|---|---|
goo | boolean | true | Master switch. false renders a plain shadcn HoverCardContent. |
flow | boolean | true | The 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. |
bridge | boolean | true | The bulb and lumpy neck between the trigger and the card. Not used by bloom. |
wobble | boolean | true | The open overshoot and settle. |
momentum | boolean | true | The launch away from the trigger. Not used by bloom. |
fade | boolean | true | The content fades in once the goo settles. |
openSlosh | boolean | number | true | On open, every edge bulges past rest, rebounds, and wobbles. A number from 0 to 2 sets the strength. |
openDrips | boolean | number | true | On open, drops splash off all around, kept off the trigger. A number from 0 to 2 sets the strength. |
openDripAmount | number | 1 | Splash drop count, 0 to 3. |
openDripSize | number | 1 | Splash drop size, 0.3 to 2.5. |
openDripFling | number | 1 | How far the drops are flung, 0 to 3. |
openDripVariety | number | 0.7 | Mix of globs and specks, 0 to 1. |
sloshVariety | number | 1 | How differently each side bulges, 0 to 1. 0 is an even, centred bulge. |
closeSlosh | boolean | number | true | On 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. |
speed | number | 1 | Animation speed multiplier. |
preset | 'subtle' | 'playful' | 'wild' | app config, then playful | The 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.