Sheet
MD3 side and bottom sheets.
Walkthrough
1. Sides
Four edges. A bottom sheet is what a phone wants; the sides suit a desktop panel.
<script lang="ts"> import { Button, Sheet } from 'omaris'; let side = $state<'start' | 'end' | 'top' | 'bottom'>('end'); let open = $state(false); function show(next: typeof side) { side = next; open = true; }</script><Button variant="outlined" size="xs" onclick={() => show('start')}>start</Button><Button variant="outlined" size="xs" onclick={() => show('end')}>end</Button><Button variant="outlined" size="xs" onclick={() => show('top')}>top</Button><Button variant="outlined" size="xs" onclick={() => show('bottom')}>bottom</Button><Sheet bind:open {side} title="Filters" description="side = {side}"> <p class="text-body-md text-muted-foreground">Drag the handle to dismiss it, or press outside.</p></Sheet> 2. Snap points
snapPoints are fractions of the screen a bottom sheet settles at, so it can be a peek, a half sheet and a full one without three components.
<script lang="ts"> import { Button, Sheet } from 'omaris'; let open = $state(false); let snap = $state(0);</script><Button variant="tonal" onclick={() => (open = true)}>Open a snapping sheet</Button><Sheet bind:open bind:snap side="bottom" size="full" snapPoints={[0.25, 0.6, 1]} title="Nearby drivers" description="Drag it up and down"> <div class="flex flex-col gap-3"> {#each { length: 10 }, i (i)} <div class="h-12 rounded-shape-md bg-surface-container"></div> {/each} </div></Sheet> 4. Persistent
modal={false} is a panel, not an interruption: no backdrop, and the page behind stays live. With inline it sits inside its own container, so a map keeps its controls and a screen keeps its navigation bar. Bind snap and the page can move it — a focused search box lifts it, a trip drops it.
The page behind: still scrollable, tappable, and where the map would be.
<script lang="ts"> import { Button, Input, List, ListItem, Sheet, Text } from 'omaris'; let snap = $state(0.4); const PLACES = ['Citadel', 'Ankawa', '60m Street', 'Bakhtiari', 'Family Mall', 'Gulan Park'];</script><div class="relative h-96 w-full overflow-clip rounded-shape-lg bg-surface-container"> <div class="grid h-full place-items-start p-4"> <Text variant="body-sm" tone="muted"> The page behind: still scrollable, tappable, and where the map would be. </Text> </div> <Sheet open inline modal={false} dismissible={false} side="bottom" size="full" snapPoints={[0.25, 0.55, 1]} bind:snap classes={{ root: 'border-t border-border' }} > <div class="flex flex-col gap-3"> <Input placeholder="Where to?" onfocus={() => (snap = 1)} /> <div class="flex gap-2"> <Button size="xs" variant="tonal" onclick={() => (snap = 0.25)}>Peek</Button> <Button size="xs" variant="tonal" onclick={() => (snap = 0.55)}>Half</Button> <Button size="xs" variant="tonal" onclick={() => (snap = 1)}>Full</Button> </div> <List> {#each PLACES as place (place)} <ListItem headline={place} supportingText="Tap to go" onclick={() => (snap = 0.25)} /> {/each} </List> </div> </Sheet></div>