Sheet

A sheet is a swipeable overlay that slides in from an edge of the screen.

<Dialog>
  <Button>Open Sheet</Button>
  <Sheet>
    <DialogContent>
      <DialogHeader>
        <DialogTitle>Sheet Title</DialogTitle>
        <DialogDescription>This is a sheet description.</DialogDescription>
      </DialogHeader>
      <DialogBody>
        <p>Sheet content goes here.</p>
      </DialogBody>
      <DialogFooter>
        <Button slot="close">Close</Button>
      </DialogFooter>
    </DialogContent>
  </Sheet>
</Dialog>

Installation

pnpm dlx shadcn@latest add @dotui/sheet

Usage

import { Button } from "@/components/ui/button"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Sheet } from "@/components/ui/sheet"
<Dialog>
  <Button>Open Sheet</Button>
  <Sheet>
    <DialogContent>Sheet content</DialogContent>
  </Sheet>
</Dialog>

Anatomy

A Sheet has no built-in trigger. Wrap it in a Dialog with a Button child as the trigger, and put your content inside DialogContent. A sheet can also hold a menu or a listbox directly — that's how pickers render on mobile.

import { Button } from "@/components/ui/button"
import { Dialog, DialogContent } from "@/components/ui/dialog"
import { Sheet, SheetHandle } from "@/components/ui/sheet"
<Dialog>
  <Button />
  <Sheet>
    <DialogContent>
      <SheetHandle />
    </DialogContent>
  </Sheet>
</Dialog>

SheetHandle is a visible swipe affordance. The whole sheet swipes: it rides the browser's native scrolling, so it follows the finger with momentum and rubber-banding for free.

Position

position anchors the sheet to an edge: bottom (the default), top, start, end, or physical left and right. start and end mirror in right-to-left locales. swipeDirection defaults to the same edge.

<Sheet position="end">
  <DialogContent>...</DialogContent>
</Sheet>

Snap points

snapPoints stops the sheet partway open. Each value is how much of the sheet shows, in pixels or as a CSS length — percentages are of the sheet's size. It opens at the first one and drags up to its full height.

<Sheet snapPoints={[240]}>
  <DialogContent>...</DialogContent>
</Sheet>

Open state

Rendered under a Dialog, the sheet shares the dialog's open state, so the trigger Button opens it with no wiring. To drive it yourself, pass isOpen with onOpenChange (or defaultOpen for uncontrolled).

const [isOpen, setIsOpen] = React.useState(false)

<Sheet isOpen={isOpen} onOpenChange={setIsOpen}>
  <DialogContent>...</DialogContent>
</Sheet>

Dismissal

The sheet dismisses on swipe, outside interaction, and Escape. preventDismissal blocks all three; with snap points, the sheet still swipes between them.

<Sheet preventDismissal>
  <DialogContent>...</DialogContent>
</Sheet>

Examples

Basic Sheet

Settings Panel

Place Details

Nested Sheets

Scrollable Content

Form Sheet

API Reference

Sheet

A sheet is a swipeable overlay that slides in from an edge of the viewport.

PropType
ReactNode
boolean
boolean
Element
union
boolean
function
(string | number)[]
boolean
union

SheetHandle

A visible swipe affordance.

Supports all div attributes.

PropType

Last updated on 10/20/2026