Acrylic
Components

Sheet

Radix Dialog as an edge-anchored panel — a frosted acrylic surface that slides in over a blurred overlay.

A Radix Dialog dressed as a slide-in panel: a translucent acrylic surface anchored to any edge, over an 8px-blur overlay. Drop-in API-compatible with the shadcn Sheet — pass side to choose which edge it enters from.

Installation

npx shadcn add https://acrylic-ui.vercel.app/r/sheet.json

Usage

import { Button } from "@/registry/acrylic/button"
import {
  Sheet,
  SheetClose,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/registry/acrylic/sheet"

<Sheet>
  <SheetTrigger asChild>
    <Button variant="neutral">Open</Button>
  </SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Edit profile</SheetTitle>
      <SheetDescription>Make changes to your profile here.</SheetDescription>
    </SheetHeader>
    {/* form body — add px-4, SheetContent only sets gap-4 */}
    <SheetFooter>
      <Button type="submit">Save changes</Button>
      <SheetClose asChild>
        <Button variant="neutral">Close</Button>
      </SheetClose>
    </SheetFooter>
  </SheetContent>
</Sheet>

Sides

The side prop on SheetContent anchors the panel to any edge — top · right (default) · bottom · left — each with its own slide-in direction.

Notes

  • Built on @radix-ui/react-dialog, the same primitive as Dialog, so focus trapping, scroll locking, and Escape-to-close come for free.
  • Exports Sheet, SheetTrigger, SheetClose, SheetContent, SheetHeader, SheetFooter, SheetTitle, and SheetDescription — a faithful mirror of the shadcn API.
  • The panel is the frosted acrylic material (translucent tint + backdrop-blur) over an 8px-blur overlay; a built-in X sits in the top-right corner.
  • SheetContent only sets gap-4, so give any form body its own horizontal padding (e.g. px-4) to align it with the header and footer.
  • Drag-to-dismiss is a touch affordance — a mouse cannot drag the panel. With a cursor, press-and-move already belongs to the browser (selecting text, scrolling); taking it made the sheet slide away while the user was highlighting a sentence, and no amount of arbitration fixed that reliably — at the few pixels where a drag has to commit, the selection has not formed yet, and committing captures the pointer, which kills it. Cursors close via the ✕, Escape, or the overlay.
  • A top/bottom sheet needs its scrollable body in a nested container — put overflow-y-auto on a child, never on SheetContent itself. touch-action is read from the scroll container that implements the pan, so a nested child scrolls natively; on the panel it makes the panel that container, whose touch-action forbids the very axis it needs, and the body cannot be scrolled by finger at all.
  • Content that owns its own pointer gestures (a slider, a canvas) can opt out of the drag entirely with data-acr-no-drag on it or any ancestor inside the panel.

On this page