GitHub

Sheet

A panel that slides in from any edge of the screen, complementing the main content.

CMSPayload CMS Integration

Sheets work well for displaying CMS forms, filters, navigation menus, or detailed content panels.

CMS Demo

See how content editors configure sheets in a CMS:

Loading...
CMS ConfigurationSimulates Payload CMS sheet configuration

Basic Usage

Loading...
SheetSliding panel overlay

Installation

pnpm add @corew500/ui

Usage

import {
  Sheet,
  SheetTrigger,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetDescription,
  SheetFooter,
  SheetClose,
} from "@mordecai-design-system/ui"
<Sheet>
  <SheetTrigger>Open Sheet</SheetTrigger>
  <SheetContent>
    <SheetHeader>
      <SheetTitle>Sheet Title</SheetTitle>
      <SheetDescription>Description here</SheetDescription>
    </SheetHeader>
    <p>Sheet content</p>
    <SheetFooter>
      <SheetClose>Close</SheetClose>
    </SheetFooter>
  </SheetContent>
</Sheet>

Examples

Sides

// Right (default)
<Sheet>
  <SheetContent side="right">From right</SheetContent>
</Sheet>

// Left
<Sheet>
  <SheetContent side="left">From left</SheetContent>
</Sheet>

// Top
<Sheet>
  <SheetContent side="top">From top</SheetContent>
</Sheet>

// Bottom
<Sheet>
  <SheetContent side="bottom">From bottom</SheetContent>
</Sheet>

Without Close Button

<SheetContent showCloseButton={false}>
  <SheetHeader>
    <SheetTitle>Custom Close</SheetTitle>
  </SheetHeader>
  <SheetFooter>
    <SheetClose asChild>
      <Button>Close Sheet</Button>
    </SheetClose>
  </SheetFooter>
</SheetContent>

Controlled

const [open, setOpen] = useState(false)

<Sheet open={open} onOpenChange={setOpen}>
  <SheetTrigger>Open</SheetTrigger>
  <SheetContent>
    <Button onClick={() => setOpen(false)}>
      Close programmatically
    </Button>
  </SheetContent>
</Sheet>

With Form

<SheetContent>
  <SheetHeader>
    <SheetTitle>Edit Profile</SheetTitle>
    <SheetDescription>
      Make changes to your profile here.
    </SheetDescription>
  </SheetHeader>
  <form className="py-4 space-y-4">
    <Input placeholder="Name" />
    <Input type="email" placeholder="Email" />
  </form>
  <SheetFooter>
    <SheetClose asChild>
      <Button variant="outline">Cancel</Button>
    </SheetClose>
    <Button type="submit">Save changes</Button>
  </SheetFooter>
</SheetContent>

Sub-components

| Component | Description | |-----------|-------------| | Sheet | Root component managing open state | | SheetTrigger | Button that opens the sheet | | SheetContent | The sliding panel | | SheetHeader | Header area | | SheetTitle | Main heading | | SheetDescription | Supporting text | | SheetFooter | Footer with actions | | SheetClose | Button to close | | SheetOverlay | Background overlay |

Props

SheetContent

PropTypeDefaultDescription
showCloseButtonenumtrueWhether to display the close button in the top-right corner.
initialFocusenum—Determines the element to focus when the dialog is opened. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (first tabbable element or popup). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing.
finalFocusenum—Determines the element to focus when the dialog is closed. - `false`: Do not move focus. - `true`: Move focus based on the default behavior (trigger or previously focused element). - `RefObject`: Move focus to the ref element. - `function`: Called with the interaction type (`mouse`, `touch`, `pen`, or `keyboard`). Return an element to focus, `true` to use the default behavior, or `false`/`undefined` to do nothing.
styleenum—Style applied to the element, or a function that returns a style object based on the component’s state.
classNameenum—CSS class applied to the element, or a function that returns a class based on the component’s state.
renderenum—Allows you to replace the component’s HTML element with a different tag, or compose it with another component. Accepts a `ReactElement` or a function that returns the element to render.
sideenumright—

Sheet

PropTypeDefaultDescription
openenum—Whether the dialog is currently open.
defaultOpenenumfalseWhether the dialog is initially open. To render a controlled dialog, use the `open` prop instead.
modalenumtrueDetermines if the dialog enters a modal state when open. - `true`: user interaction is limited to just the dialog: focus is trapped, document page scroll is locked, and pointer interactions on outside elements are disabled. - `false`: user interaction with the rest of the document is allowed. - `'trap-focus'`: focus is trapped inside the dialog, but document page scroll is not locked and pointer interactions outside of it remain enabled.
onOpenChange(open: boolean, eventDetails: DialogRootChangeEventDetails) => void—Event handler called when the dialog is opened or closed.
onOpenChangeComplete(open: boolean) => void—Event handler called after any animations complete when the dialog is opened or closed.
disablePointerDismissalenumfalseDetermines whether the dialog should close on outside clicks.
actionsRefRefObject<DialogRootActions>—A ref to imperative actions. - `unmount`: When specified, the dialog will not be unmounted when closed. Instead, the `unmount` function must be called to unmount the dialog manually. Useful when the dialog's animation is controlled by an external library. - `close`: Closes the dialog imperatively when called.
handleDialogHandle<unknown>—A handle to associate the dialog with a trigger. If specified, allows external triggers to control the dialog's open state. Can be created with the Dialog.createHandle() method.
triggerIdstring—ID of the trigger that the dialog is associated with. This is useful in conjunction with the `open` prop to create a controlled dialog. There's no need to specify this prop when the popover is uncontrolled (i.e. when the `open` prop is not set).
defaultTriggerIdstring—ID of the trigger that the dialog is associated with. This is useful in conjunction with the `defaultOpen` prop to create an initially open dialog.

Sheet vs Drawer

Both Sheet and Drawer slide in from screen edges, but they have different behaviors:

| Feature | Sheet | Drawer | |---------|-------|--------| | Interaction | Click-based | Swipe support | | Mobile | Works well | Optimized | | Snap points | No | Yes | | Handle | No | Yes (bottom) |

Use Sheet for desktop-focused panels and Drawer for mobile-first interactions.