Component
Vue Bottom Sheet Component
<DomBottomSheet>A modal content sheet with configurable snap heights, a draggable and keyboard-operable handle, scrolling body, and pinned footer. Uses the shared drawer for focus, dismissal, and scroll locking. Works standalone or in the DomAppShell overlay slot.
Read, expand, and reply
Project discussion
npm install @getdom/studio<script setup>
import '@getdom/studio/style.css';
import { ref } from 'vue';
import { DomBottomSheet, DomButton, DomTextareaComposer } from '@getdom/studio';
const open = ref(false);
const reply = ref('');
const replies = ref([]);
/** Adds a local comment and clears the draft while leaving the sheet open. */
function addComment(value) {
if (!value.trim()) return;
replies.value.push(value.trim());
reply.value = '';
}
</script>
<template>
<div class="flex min-h-48 items-center justify-center bg-secondary/20 p-6">
<DomButton @click="open = true">Open project notes</DomButton>
<DomBottomSheet v-model="open" title="Project notes" :snap-points="[0, 0.4, 0.7, 0.95]" :initial-snap-point="0.7">
<div class="space-y-5 text-sm leading-7 text-muted-fg">
<p class="font-semibold text-canvas-fg">A calmer project overview</p>
<p>Keep the next action visible, give recent work a little more space, and move secondary details into the project sheet.</p>
<p>The first review is on Thursday. We’ll walk through the inbox, check how messages move into the archive, and try replying on a phone.</p>
<p>Bring one example of a task that currently takes too many steps. We’ll use those examples to choose the next improvement.</p>
<p>The aim is a useful first release: a clear list, a reliable reply flow, and a way to undo changes.</p>
<div v-for="(comment, index) in replies" :key="index" class="rounded-xl bg-secondary p-4"><p class="font-medium text-canvas-fg">You</p><p class="whitespace-pre-wrap">{{ comment }}</p></div>
<p v-if="replies.length" role="status" class="text-xs">Comment added to this preview.</p>
</div>
<template #footer><DomTextareaComposer v-model="reply" chrome="none" aria-label="Comment on project notes" placeholder="Add a comment…" :rows="1" :max-rows="3" submit-label="Add comment" :submit-on-enter="false" @submit="addComment" /></template>
</DomBottomSheet>
</div>
</template>
Sizing and interaction
snapPoints are fractions of the available sheet viewport, capped to leave a top safe-area gap. This example uses [0, 0.4, 0.7, 0.95]. Zero enables drag dismissal. Without zero, dragging stops at the smallest visible height. Escape and Close remain available.
Drag the handle to resize; the body keeps native scrolling at every height. Click the handle to cycle, or focus it and use Arrow Up/Down, Home, and End. Focusing an input expands the sheet to its largest stop. An interrupted gesture restores the previous stop.
Use v-model:snapPoint for a controlled height. Otherwise the sheet resets to initialSnapPoint on each open. Content remains mounted, so unsent input survives dismissal.
The standalone sheet teleports to its document body. Inside DomAppShell, put it in #overlay for containment, safe areas, and the shell’s keyboard sizing. Explicit contained requires a positioned, sized parent. The footer stays pinned while the body scrolls.
Try the full-screen inbox for the combined swipe, sheet, and reply flow. Check software keyboard behaviour on target devices; an iframe preview cannot reproduce its containing page’s visual viewport.
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
modelValue | boolean | boolean | false | Whether the modal sheet is open. |
title | string | string | '' | Visible title and accessible dialog name. |
label | string | string | 'Details' | Accessible dialog name when supplying a custom header without a title. |
snapPointsts | array | Array<number> | [0,0.5,0.9] | Fractions of the available height, from 0 to 1. Include 0 to allow drag dismissal. |
initialSnapPoint | number | number | 0.5 | Preferred height on each open, rounded to the nearest non-zero stop. |
snapPointts | number | number | null | — | Optional controlled height. Use v-model:snapPoint; null uses internal state. |
contained | boolean | boolean | — | Defaults to contained in DomAppShell, viewport otherwise. Use the shell overlay slot. |
static | boolean | boolean | false | Disable backdrop dismissal. Close and Escape remain available; omit zero from snapPoints to disable drag dismissal. |
keyboardInsetts | number | number | null | — | Optional native keyboard inset for standalone sheets. Contained sheets inherit the resized shell. |
Auto-generated from Bottom sheet.props and inline _edit hints.
Slots
| Name | Scope | Description |
|---|---|---|
| #(default) | { close, expand } | Scrollable sheet content. |
| #header | — | Custom heading content beside the close button. |
| #footer | { close, expand } | Pinned controls, such as a reply composer. |
Events
| Name | Payload | Description |
|---|---|---|
| @update:modelValue | boolean | Open or dismiss the sheet. |
| @update:snapPoint | number | The selected fraction of the available sheet viewport. |
Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.
Keyboard
- Handle: Arrow Up / DownExpand or collapse to the next visible stop.
- Handle: Home / EndChoose the smallest or largest visible stop.
- Handle: Enter / SpaceCycle through visible snap heights.
- EscapeDismiss and return focus to the opener.