Components

Sheet

Source
Headless drag-snappable edge sheet primitive with snap points, fling, and drag-to-dismiss.

Overview

Sheet is a headless @vyui/core primitive for a panel that slides in from a viewport edge and settles at one of several snap points. Dragging is driven on the main thread for native-smooth tracking, with fling-to-advance and optional drag-to-dismiss. The styled Drawer and ActionSheet components build on it.

This is a vyui-original @vyui/core primitive (the snap/drag pattern is adapted from lynx-ui). Compose it directly when you need custom snap behavior; otherwise use the styled kit components.

Anatomy

<SheetRoot>
  <SheetTrigger />
  <SheetBackdrop />
  <SheetContent>
    <SheetHandle />
    <!-- sheet body -->
  </SheetContent>
</SheetRoot>

Usage

<script setup lang="ts">
import {
  SheetBackdrop,
  SheetContent,
  SheetHandle,
  SheetRoot,
  SheetTrigger,
} from '@vyui/core'

const open = ref(false)
</script>

<template>
  <SheetRoot
    v-model:open="open"
    side="bottom"
    :snap-points="[0.25, 0.5, 0.9]"
    :default-snap-index="1"
  >
    <SheetTrigger>
      <text>Open sheet</text>
    </SheetTrigger>
    <SheetBackdrop />
    <SheetContent>
      <SheetHandle />
      <view class="p-4">
        <text>Drag the handle to snap between sizes.</text>
      </view>
    </SheetContent>
  </SheetRoot>
</template>

Features and behavior

  • side controls the edge and drag axis: top, right, bottom, or left; default is bottom.
  • snapPoints are fractions of viewport extent on that axis, low → high (e.g. [0.25, 0.5, 0.9]); default is [1] (full height or width).
  • snapIndex / v-model:snapIndex controls the current snap (0 = most closed); defaultSnapIndex seeds it.
  • A fling projects a short coast and advances by a snap; outward flings past dismissVelocity dismiss when enableDragToClose (default true).
  • dragHandleOnly restricts dragging to <SheetHandle>, leaving the body non-interactive to touch.
  • viewportHeight overrides the runtime height read; duration tunes the settle animation.

API

SheetRoot

PropDefaultType
defaultOpenfalseboolean | undefined

Initial open state when uncontrolled.

defaultSnapIndex0number | undefined

Initial snap index when uncontrolled (defaults to 0). The enter animation always slides fully in first; when this points below the largest snap the sheet then settles down to it. The index persists across close/reopen.

dismissVelocity600number | undefined

Downward velocity (px/s) at which a fling dismisses from any position (when `enableDragToClose`).

duration280number | undefined

Settle animation duration in ms. Drag release snap-back uses it directly; drag-dismiss and touch-cancel use shorter cuts of it.

enableDragToClosetrueboolean | undefined

Allow drag below the most-closed snap to dismiss. When `false` with multiple snap points, drag between snaps still works — only the dismiss branch is disabled.

handleOnlyfalseboolean | undefined

Restrict drag interaction to `<SheetHandle>` only. When `true`, the `<SheetContent>` body does not respond to touch.

openboolean | undefined

Controlled open state. Bind with `v-model:open`.

side"bottom"SheetDirection | undefined

Edge the sheet is anchored to. Controls enter/exit animation and drag axis.

snapIndexnumber | undefined

Controlled current snap index. Bind with `v-model:snapIndex`. Indexes the SORTED `snapPoints` (0 = smallest fraction = most closed). Updated by drag settles; writing it animates the open sheet to that snap.

snapPoints[1]number[] | undefined

Snap points as fractions of viewport extent on the sheet axis, low → high. e.g. `[0.25, 0.5, 0.9]`. For `top`/`bottom` this is viewport height; for `left`/`right` this is viewport width.

velocityThreshold400number | undefined

Absolute velocity (px/s) above which a fling advances by one snap regardless of position. Currently unused — the release logic (mirroring `pickRelease`) implements flick-advance via a 100ms coast projection instead. Reserved.

viewportHeightnumber | undefined

Viewport height in px. If omitted, reads from `SystemInfo.pixelHeight / pixelRatio` at runtime, falling back to `800`.

viewportWidthnumber | undefined

Viewport width in px. If omitted, reads from `SystemInfo.pixelWidth / pixelRatio` at runtime, falling back to `400`.

EventPayload
update:open[value: boolean]
update:snapIndex[value: number]

SheetContent

PropDefaultType
dragDisabledfalseboolean | undefined

Disable drag / snap / fling; open and close still animate.

fitContentfalseboolean | undefined

Hug content instead of sizing the panel to `snapPoints × viewport`. Forwarded to `SheetContentImpl`. Used by the styled `Tray`.

SheetTrigger

PropDefaultType
as"view"AsTag | undefined
asChildboolean | undefined

SheetBackdrop

PropDefaultType
dismissOnTaptrueboolean | undefined

Close the sheet when the backdrop is tapped.

SheetHandle

PropDefaultType
hiddenboolean | undefined

Hide the default handle styling.

Accessibility

  • Provide a visible label or handle affordance so the sheet is discoverable and draggable.
  • The backdrop dims and (by default) closes the sheet; ensure the open state is reflected to assistive tech via the content semantics.

Platform notes

  • Drag tracking and bounce run through main-thread (MTS) touch worklets, so motion stays smooth off the background thread.
  • id is required by the bounce system to select the container on the main thread; it is auto-generated when omitted.
  • Drawer — the styled @vyui/kit sheet.
  • ActionSheet — a styled list-of-actions sheet.
  • Dialog — a centered modal alternative.