Sheet
An edge panel
Sheet is Dialog with a different name, and SheetContent takes the same side. The rename exists so a call site says which shape it means; there is only one implementation to keep honest.
<Sheet>
<SheetTrigger>
<Button variant="secondary">Filters</Button>
</SheetTrigger>
<SheetContent side="right">
<SheetTitle>Filters</SheetTitle>
<div class="space-y-4">
<label class="flex items-center justify-between text-sm">
<span>Paid only</span>
<Switch checked />
</label>
<label class="flex items-center justify-between text-sm">
<span>Include refunded</span>
<Switch />
</label>
<div class="space-y-2">
<Label for="channel">Channel</Label>
<p class="text-muted text-xs">Web, Instagram, WhatsApp</p>
</div>
</div>
<SheetClose>
<Button class="w-full">Apply</Button>
</SheetClose>
</SheetContent>
</Sheet>From the left
A left sheet is where navigation goes on a narrow viewport — AppShell already does exactly this, moving the Sidebar, the search control and the account menu into one below md.
<Sheet>
<SheetTrigger>
<Button variant="ghost">Menu</Button>
</SheetTrigger>
<SheetContent side="left">
<SheetTitle>Navigation</SheetTitle>
<nav class="flex flex-col gap-1 text-sm">
<a
href="/blocks/templates/dashboard"
class="hover:bg-hover rounded-md px-3 py-2">Dashboard</a
>
<a href="/blocks/orders" class="hover:bg-hover rounded-md px-3 py-2">Orders</a>
<a href="/blocks/settings" class="hover:bg-hover rounded-md px-3 py-2"
>Settings</a
>
</nav>
</SheetContent>
</Sheet>API
Sheet declares no components of its own: every part is Dialog's,
renamed. One implementation, and a call site that reads as what it is.
Sheet→DialogSheetTrigger→DialogTriggerSheetContent→DialogContentSheetTitle→DialogTitleSheetClose→DialogClose