icon

Morainev0.5.0

Sheet
overlayssheet

Sheet

Slide-in panel overlay from any screen edge with structured content slots.

Import#

import { Sheet } from 'moraine'

Slot Structure#

Wrapper trigger with optional backdrop and a sliding panel with title, body, and footer slots.

trigger
├── overlay (optional)
└── content (portal)
├── header (optional)
│ ├── wrapper (optional)
│ │ ├── title (optional)
│ │ └── description (optional)
│ ├── actions (optional)
│ └── close (optional)
├── body (optional)
└── footer (optional)

Examples#

Variants#

Inset layout with custom close content or hidden close control.

function Variants() {
return (
<div class="flex flex-wrap gap-3 items-center">
<Sheet
inset
title="Inset sheet"
close={<span class="text-xs font-semibold">Done</span>}
body="Inset sheet with custom close content."
>
<Button variant="secondary">Inset + custom close</Button>
</Sheet>
<Sheet title="No close button" close={false} body="Close button is hidden for this sheet.">
<Button variant="outline">Close=false</Button>
</Sheet>
</div>
)
}

Sides#

Open sheet from each side with shared shell slots.

function Sides() {
const SIDES = ['left', 'right', 'top', 'bottom'] as const
return (
<div class="flex flex-wrap gap-3 items-center">
<For each={SIDES}>
{(side) => (
<Sheet
side={side}
title={`Sheet ${side}`}
description={`This sheet opens from ${side}.`}
body={<p class="text-sm text-foreground">Body content from {side} side.</p>}
>
<Button variant="outline" size="sm">
{side}
</Button>
</Sheet>
)}
</For>
</div>
)
}

Dismiss Control#

Prevent close on outside interaction and Escape while counting attempts.

function DismissControl() {
const [preventedCloseCount, setPreventedCloseCount] = createSignal(0)
return (
<div class="flex flex-wrap gap-3 items-center">
<Sheet
defaultOpen
dismissible={false}
onClosePrevent={() => setPreventedCloseCount((value) => value + 1)}
title="Persistent sheet"
body={
<p class="text-sm text-foreground">
Prevented close attempts: <span class="font-medium">{preventedCloseCount()}</span>
</p>
}
>
<Button variant="outline">Dismiss blocked</Button>
</Sheet>
</div>
)
}

API Reference#

Attributes#

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

Props#

PropTypeDefaultDescription
actionJSX.Element—
Additional action elements to render in the header.
bodyJSX.Element—
Custom element to render in the scrollable body slot.
childrenJSX.Element—
Trigger element that opens the sheet.
classClassValue—
Class applied to the component root or trigger element.
classesSheetT.Classes | undefined——
closeboolean | JSX.Elementtrue
Whether to show a close button, or a custom element to use as one.
defaultOpenboolean | undefined—
Initial open state when uncontrolled.
descriptionJSX.Element—
Secondary description displayed below the title.
dismissibleboolean | undefined—
Whether outside interaction and Escape should dismiss the shell.
footerJSX.Element—
Custom element to render in the footer slot.
headerJSX.Element—
Custom element to render in the header slot.
idstring | undefined—
Unique identifier used to derive the content id.
insetboolean | 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——
side"bottom" | "top" | "right" | "left" | undefined——
styleJSX.CSSProperties | undefined——
stylesSheetT.Styles | undefined——
titleJSX.Element—
Primary title displayed in the sheet header.
transitionboolean | undefinedtrue
Whether to enable transition animations.