icon

Morainev0.5.0

Popover
overlayspopover

Popover

Click-triggered floating content panel anchored to a trigger element.

Import#

import { Popover } from 'moraine'

Slot Structure#

Wrapper trigger with a floating content portal containing the body.

trigger
└── content (portal)
└── body

Examples#

Placements#

Click trigger with four placement variants.

function Placements() {
const PLACEMENTS = ['top', 'right', 'bottom', 'left'] as const
return (
<div class="flex flex-wrap gap-3 items-center">
<For each={PLACEMENTS}>
{(placement) => (
<Popover
placement={placement}
content={
<div class="space-y-1">
<p class="text-sm font-medium capitalize">{placement}</p>
<p class="text-xs text-muted-foreground">Popover content aligned to {placement}.</p>
</div>
}
>
<Button variant="outline" size="sm">
{placement}
</Button>
</Popover>
)}
</For>
</div>
)
}

Hover Mode#

Hover-based popover using open and close delays.

function HoverMode() {
return (
<div class="flex flex-wrap gap-3 items-center">
<Popover
mode="hover"
openDelay={180}
closeDelay={120}
content={
<div class="space-y-1">
<p class="text-sm font-medium">Hover Card</p>
<p class="text-xs text-muted-foreground">
This popover opens on hover and closes after delay.
</p>
</div>
}
>
<Button variant="outline">Hover me</Button>
</Popover>
</div>
)
}

Dismiss Control#

Prevent closing on outside interaction and Escape key.

function DismissControl() {
const [preventedCloseCount, setPreventedCloseCount] = createSignal(0)
return (
<div class="flex flex-wrap gap-3 items-center">
<Popover
defaultOpen
dismissible={false}
onClosePrevent={() => setPreventedCloseCount((value) => value + 1)}
content={
<div class="space-y-1">
<p class="text-sm font-medium">Persistent popover</p>
<p class="text-xs text-muted-foreground">
Prevented close attempts: {preventedCloseCount()}
</p>
</div>
}
>
<Button variant="secondary">Try close me</Button>
</Popover>
</div>
)
}

API Reference#

Attributes#

Slottrigger3 attributes
Element users activate to open the popover.

ARIA Attributes

3
ARIA AttributeDescription
aria-controls
References the controlled element while the related content is mounted.
aria-describedby
References descriptive text associated with the control.
aria-expanded
Indicates whether the controlled content is expanded.

Props#

PropTypeDefaultDescription
childrenJSX.Element
The reference element that triggers the popover.
classClassValue
Class applied to the component root or trigger element.
classesPopoverT.Classes | undefined
closeDelaynumber | undefined100
Delay in milliseconds before closing in hover mode.
contentJSX.Element
Content to render inside the popover body.
defaultOpenboolean | undefined
dismissibleboolean | undefined
forceMountboolean | undefined
idstring | undefined
modalboolean | undefined
modePopoverMode | undefinedclick
Interaction mode for triggering the popover.
onClosePrevent(() => void) | undefined
onOpenChange((open: boolean) => void) | undefined
openboolean | undefined
openDelaynumber | undefined100
Delay in milliseconds before opening in hover mode.
placementPlacement | undefined
preventScrollboolean | undefined
refJSX.HTMLElementTags["span"] extends { ref?: infer Ref; } ? Ref : never | undefined
side"bottom" | "top" | "right" | "left" | undefined
styleJSX.CSSProperties | undefined
stylesPopoverT.Styles | undefined