icon

Morainev0.5.0

Popup
overlayspopup

Popup

Low-level overlay primitive providing portal, backdrop, and content positioning.

Import#

import { Popup } from 'moraine'

Slot Structure#

Wrapper trigger with an optional backdrop and a floating content portal.

trigger
├── overlay (optional)
└── content (portal)

Examples#

Default Container#

Popup provides only container + overlay. Content styling is fully custom.

function DefaultContainer() {
return (
<Popup
content={
<div class="p-4 b-1 b-border rounded-xl bg-background ring-1 ring-foreground/10 shadow-md">
<h3 class="text-sm font-semibold">Popup content</h3>
<p class="text-sm text-muted-foreground mt-1">
This content controls its own spacing and visuals.
</p>
</div>
}
>
<Button>Open popup</Button>
</Popup>
)
}

Dismiss Control#

Block outside dismiss and count prevent-close attempts.

function DismissControl() {
const [preventedCloseCount, setPreventedCloseCount] = createSignal(0)
return (
<Popup
dismissible={false}
onClosePrevent={() => setPreventedCloseCount((value) => value + 1)}
content={
<div class="p-4 b-1 b-border rounded-xl bg-background ring-1 ring-foreground/10 shadow-md">
<h3 class="text-sm font-semibold">Persistent popup</h3>
<p class="text-sm text-muted-foreground mt-1">Refresh to dismiss</p>
<p class="text-sm text-muted-foreground mt-1">
Prevented close attempts: {preventedCloseCount()}
</p>
</div>
}
>
<Button variant="secondary">Dismiss blocked</Button>
</Popup>
)
}

Scrollable Overlay Mode#

Scrollable overlay keeps content in flow while preserving the backdrop.

function ScrollableOverlayMode() {
const SCROLLABLE_LINES = Array.from({ length: 48 }, (_, index) => `Popup line ${index + 1}`)
return (
<Popup
scrollable
content={
<div class="p-4 b-1 b-border rounded-xl bg-background ring-1 ring-foreground/10 shadow-md">
<h3 class="text-sm font-semibold">Scrollable Popup</h3>
<div class="mt-2 space-y-1">
<For each={SCROLLABLE_LINES}>
{(line) => <p class="text-sm text-foreground">{line}</p>}
</For>
</div>
</div>
}
>
<Button variant="outline">Open scrollable popup</Button>
</Popup>
)
}

API Reference#

Attributes#

Slottrigger0 attributes
Element users activate to open the popup.
No attribute metadata for this slot.

Props#

PropTypeDefaultDescription
childrenJSX.Element
Element that triggers the popup or additional content.
classClassValue
Class applied to the component root or trigger element.
classesPopupT.Classes | undefined
contentComponentOrElement<ModalContentContext> | undefined
Modal content rendered inside the content surface.
defaultOpenboolean | undefined
Initial open state when uncontrolled.
dismissibleboolean | undefined
Whether outside interaction and Escape should dismiss the shell.
fullscreenboolean | undefinedfalse
Whether the popup should cover the entire viewport.
idstring | undefined
Unique identifier used to derive the content id.
layout"default" | "scrollable" | "fullscreen" | undefined
onClosePrevent(() => void) | undefined
Called when a dismissal attempt is blocked.
onOpenChange((open: boolean) => void) | undefined
Called whenever the open state changes.
openboolean | undefined
Controlled open state.
overlayboolean | undefined
Whether to render the overlay element.
refJSX.HTMLElementTags["span"] extends { ref?: infer Ref; } ? Ref : never | undefined
scrollableboolean | undefinedfalse
Whether to allow scrolling within the popup.
styleJSX.CSSProperties | undefined
stylesPopupT.Styles | undefined