Yugen UI

Sheet

Sheet is an adaptive overlay with one API and one content: a side panel on wide screens, a draggable bottom sheet on phones.

Built on Radix Dialog, so focus trapping, Esc, scroll locking and the dialog role come built in. Below the breakpoint (768px by default) Sheet becomes a bottom sheet with 16px rounded top corners: drag it by the handle or the header, and it stops at the snapPoints (fractions of the screen height). Flick to jump between snap points, swipe down to close. Content only scrolls at the highest snap point; the footer stays at the bottom of the screen and leaves room for the safe area. On wide screens it is a start / end panel (flipped in RTL) with the same three widths as Drawer. With reduced motion, every slide and bounce becomes instant.
Yugen Labs · experimentalThis component is outside SemVer: its API can change in a minor release, and What's new says so. Versioning policy

Import

Install from npm, copy the source into your project with @yugen-ui/cli or the shadcn CLI, or import directly when working in this repo.

TSX
// npm install yugen-uiimport {  Sheet, SheetTrigger, SheetContent, SheetHeader, SheetTitle, SheetDescription,  SheetBody, SheetFooter, SheetClose,} from "yugen-ui";

Variants

Each tile is a standalone example: hover to copy, or press Code to see the source.

Bottom sheet & snap point

mode="bottom" forces the bottom sheet (you can try it with a mouse on desktop). snapPoints [0.45, 0.9]; content only scrolls at the 90% snap point.

Non-modal

modal={false}: no backdrop and no focus trap, so the page behind stays usable. One snap point at 30%; swipe down to close.

Start panel, choice required

side="start" size="medium" on desktop; dismissible={false} blocks Esc, backdrop clicks and swiping down, so people have to pick an action.

Usage

Do
  • Always include a SheetTitle; add a SheetDescription when the title doesn't give enough context.
  • Put the primary action in SheetFooter. On phones it stays within thumb reach, even at a low snap point.
  • Make the lowest snap point just big enough for the common task (a quick look) and use a higher one for details; 2–3 snap points at most.
Don't
  • Don't use Sheet for short confirmations or destructive actions. Use Dialog modalType="alert".
  • Don't put horizontal drag areas (sliders, maps) in the header. The header and the handle drag the sheet.
  • Don't open a Sheet on top of a Sheet. Use dismissible={false} only when a choice is truly required.

Props

Prop · TypeDefaultDescription
open / defaultOpen / onOpenChangeboolean / boolean / (open) => voidDefault: —Open state (controlled or uncontrolled).
mode"auto" | "side" | "bottom"Default: "auto"auto: panel when the viewport is ≥ breakpoint, bottom sheet when it is narrower.
breakpoint"lg" | "xl" | "2xl" | "3xl" | "4xl" | "5xl" | numberDefault: "3xl"Minimum viewport width for the panel form, with the same tokens as AppShell: lg 32rem · xl 36rem · 2xl 42rem · 3xl 48rem · 4xl 56rem · 5xl 64rem. A px number is deprecated (removed in 1.0).
side"start" | "end"Default: "end"Edge the panel slides in from; flipped in RTL.
size"small" | "medium" | "large"Default: "small"Panel width: 320 / 592 / 940px.
snapPointsnumber[]Default: [0.5, 0.9]Bottom sheet heights (fractions of the viewport height, 0–1).
snapPoint / defaultSnapPoint / onSnapPointChangenumber / number / (snap) => voidDefault: —Current snap point; defaults to the lowest. When uncontrolled, it starts again from defaultSnapPoint each time the sheet opens.
modalbooleanDefault: truefalse: no backdrop, no focus trap or scroll lock, and no closing on an outside click.
dismissiblebooleanDefault: truefalse: blocks closing with Esc, a backdrop click or swiping down.
SheetContent.handle / handleLabelboolean / stringDefault: true / "Change height"Bottom sheet handle; it is a button (Enter, ↑ / ↓) when there are 2 or more snap points.
SheetContent.material"glass" | "glass-clear"Default: —Yugen Labs — a glass surface. A glass bottom sheet is inset from the screen edges, rounded on all four corners, and turns opaque at the highest snap point.
SheetHeader.actionReactNodeDefault: —Element at the end of the header row, usually a close button.
data-sheet-no-dragattributeDefault: —Add it to a child element so touches on it don't drag the sheet.

Messages

Text built into the component: labels, aria-labels, screen reader announcements.

English by default. Change it with the messages prop of YugenProvider, by the namespace below; messagesVi has the Vietnamese set. See Interface language.

messages.sheet

Key · TypeDefault (English)messagesVi
handlestring

Nhãn tay nắm đổi nấc chiều cao của bottom sheet (phần "(50%)" được thêm sau).

Default (English)"Change height"messagesVi"Đổi chiều cao"