Popover

Gooey popover whose panel oozes out of the trigger through an SVG goo filter — a liquid neck that stretches and pinches — with crisp content fading in on top, plus a Morph variant that clip-morphs open from the trigger corner. Click or hover trigger, controlled or uncontrolled.

Gooey Popover

popover.tsx

Composable Popover, PopoverTrigger, PopoverContent; the panel oozes out of the trigger through an SVG goo filter with a liquid neck, crisp content fading in on top. Click or hover, controlled or uncontrolled.

Install

$ bunx --bun shadcn add @beui/popover

API Reference

Popover

open?
boolean

Controlled open state.

defaultOpen?
boolean

Uncontrolled initial open state.

false
onOpenChange?
((open: boolean) => void)
trigger?
"click" | "hover"

How the popover is summoned. Default "click".

click
side?
"bottom" | "top"

Which side of the trigger the panel oozes out of. Default "bottom".

bottom
align?
"center" | "start" | "end"

Alignment along the trigger's edge. Default "center".

center
sideOffset?
number

Gap between trigger and panel, in px — the length of the gooey neck. Default 14.

14
panelRadius?
number

Corner radius of the open panel, in px. Default 16.

16
gooStrength?
number

Blur radius feeding the goo filter — higher melts more. Default 8.

8
className?
string

PopoverTrigger

children
ReactElement

A single focusable element (e.g. a Button) that opens the popover.

PopoverContent

className?
string

Morph Popover

popover-morph.tsx

Composable MorphPopover, MorphPopoverTrigger, MorphPopoverContent; the panel is laid out full size but clipped to the corner nearest the trigger, then unclips as one piece — a single-surface morph with a drop-shadow that hugs the shape. Side/align aware, controlled or uncontrolled.

Install

$ bunx --bun shadcn add @beui/popover-morph

API Reference

MorphPopover

open?
boolean

Controlled open state.

defaultOpen?
boolean

Uncontrolled initial open state.

false
onOpenChange?
((open: boolean) => void)
className?
string

MorphPopoverContent

side?
"bottom" | "top"
bottom
align?
"start" | "end"
end
sideOffset?
number

Gap between trigger and panel, in px. Default 8.

8
radius?
number

Panel corner radius, in px. Default 16.

16
className?
string

Keep in mind

Some components on this site are inspired by or recreated from existing work across the web. I'm not here to take credit; just to learn, experiment, and sometimes push things a bit further. If something looks familiar and I forgot to mention you, reach out and I'll fix that right away.

Updated