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.