Skip to content
View as Markdown

Sheet ​

The Sheet component is a slide-in panel that appears from any edge of the screen. It is backed by Base UI's Drawer primitive and includes native swipe-to-dismiss gesture support on touch devices.

Live preview in the UI Catalogue →

Import ​

tsx
import { Sheet } from "@tailor-platform/app-shell";

Basic Usage ​

tsx
<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open Settings</Sheet.Trigger>
  <Sheet.Content>
    <Sheet.Header>
      <Sheet.Title>Settings</Sheet.Title>
      <Sheet.Description>Manage your preferences.</Sheet.Description>
    </Sheet.Header>
    {/* Sheet body content */}
    <Sheet.Footer>
      <Sheet.Close render={<Button variant="outline" />}>Close</Sheet.Close>
    </Sheet.Footer>
  </Sheet.Content>
</Sheet.Root>

Sub-components ​

Sub-componentDescription
Sheet.RootManages open/close state and controls the slide direction
Sheet.TriggerElement that opens the sheet when clicked
Sheet.ContentThe main sheet panel; includes close button and backdrop when modal={true}
Sheet.HeaderLayout wrapper for title and description
Sheet.FooterLayout wrapper for action buttons
Sheet.TitleSheet title (announced by screen readers)
Sheet.DescriptionAdditional context below the title
Sheet.CloseButton that closes the sheet

Props ​

Sheet.Root Props ​

PropTypeDefaultDescription
side"top" | "right" | "bottom" | "left""right"Which edge of the screen the sheet slides in from
openboolean-Controlled open state
defaultOpenbooleanfalseInitial open state (uncontrolled)
onOpenChange(open: boolean) => void-Callback when open state changes
modalbooleantrueWhether the sheet is modal
childrenReact.ReactNode-Sheet sub-components

When modal={false}, the sheet does not render a backdrop.

Sheet.Content Props ​

PropTypeDefaultDescription
size"sm" | "md" | "lg" | "xl" | "full""sm"Max-width of the sheet panel (applies to left/right sides only)
classNamestring-Additional CSS classes

Also accepts all standard HTML <div> props.

Sheet.Header Props ​

PropTypeDefaultDescription
actionReact.ReactNode-Action buttons displayed to the right of the title area

The header renders a close button on the left, title in the center, and action buttons on the right.

Sheet.Trigger / Sheet.Close Props ​

Accept a render prop for custom element rendering (Base UI render pattern), plus standard button props.

Sizes ​

Control the width of the sheet panel using the size prop on Sheet.Content. This applies to left and right side sheets.

tsx
<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open Small</Sheet.Trigger>
  <Sheet.Content size="sm">…</Sheet.Content>  {/* 384px (24rem) — default */}
</Sheet.Root>

<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open Medium</Sheet.Trigger>
  <Sheet.Content size="md">…</Sheet.Content>  {/* 512px (32rem) */}
</Sheet.Root>

<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open Large</Sheet.Trigger>
  <Sheet.Content size="lg">…</Sheet.Content>  {/* 720px (45rem) */}
</Sheet.Root>

<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open XL</Sheet.Trigger>
  <Sheet.Content size="xl">…</Sheet.Content>  {/* 960px (60rem) */}
</Sheet.Root>

<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Open Full</Sheet.Trigger>
  <Sheet.Content size="full">…</Sheet.Content>  {/* 100% width */}
</Sheet.Root>

Sides ​

tsx
<Sheet.Root side="right">…</Sheet.Root>   {/* default — slides from right */}
<Sheet.Root side="left">…</Sheet.Root>    {/* slides from left */}
<Sheet.Root side="top">…</Sheet.Root>     {/* slides from top */}
<Sheet.Root side="bottom">…</Sheet.Root>  {/* slides from bottom */}

The swipe-to-dismiss gesture direction is automatically determined by the side prop.

Controlled Usage ​

tsx
const [open, setOpen] = useState(false);

<Sheet.Root side="right" open={open} onOpenChange={setOpen}>
  <Sheet.Trigger render={<Button />}>Open</Sheet.Trigger>
  <Sheet.Content>
    <Sheet.Header>
      <Sheet.Title>Filters</Sheet.Title>
    </Sheet.Header>
    <Sheet.Footer>
      <Button onClick={() => setOpen(false)}>Apply</Button>
    </Sheet.Footer>
  </Sheet.Content>
</Sheet.Root>;

Non-modal Sheet ​

tsx
<Sheet.Root side="right" modal={false}>
  <Sheet.Trigger render={<Button />}>Open Inspector</Sheet.Trigger>
  <Sheet.Content>
    <Sheet.Header>
      <Sheet.Title>Inspector</Sheet.Title>
    </Sheet.Header>
  </Sheet.Content>
</Sheet.Root>

Examples ​

Header with Actions ​

Place action buttons (e.g., save, edit) to the right of the title using the action prop on Sheet.Header.

tsx
<Sheet.Root side="right">
  <Sheet.Trigger render={<Button />}>Edit Record</Sheet.Trigger>
  <Sheet.Content size="lg">
    <Sheet.Header action={<Button size="sm">Save</Button>}>
      <Sheet.Title>Edit Customer</Sheet.Title>
    </Sheet.Header>
    <div className="p-4">
      <Input placeholder="Customer name" />
    </div>
  </Sheet.Content>
</Sheet.Root>

Filter Panel ​

tsx
function FilterPanel() {
  return (
    <Sheet.Root side="right">
      <Sheet.Trigger render={<Button variant="outline" />}>Filters</Sheet.Trigger>
      <Sheet.Content>
        <Sheet.Header>
          <Sheet.Title>Filter Orders</Sheet.Title>
          <Sheet.Description>Narrow down orders by criteria.</Sheet.Description>
        </Sheet.Header>
        <div className="p-4 flex flex-col gap-4">
          <Input placeholder="Customer name" />
          <Input placeholder="Order number" />
        </div>
        <Sheet.Footer>
          <Sheet.Close render={<Button variant="outline" />}>Clear</Sheet.Close>
          <Button>Apply Filters</Button>
        </Sheet.Footer>
      </Sheet.Content>
    </Sheet.Root>
  );
}

Bottom Sheet on Mobile ​

tsx
<Sheet.Root side="bottom">
  <Sheet.Trigger render={<Button />}>More Options</Sheet.Trigger>
  <Sheet.Content>
    <Sheet.Header>
      <Sheet.Title>Actions</Sheet.Title>
    </Sheet.Header>
    <div className="p-4 flex flex-col gap-2">
      <Button variant="ghost">Edit</Button>
      <Button variant="ghost">Duplicate</Button>
      <Button variant="destructive">Delete</Button>
    </div>
  </Sheet.Content>
</Sheet.Root>

Accessibility ​

  • Sheet title is announced by screen readers via Sheet.Title
  • Focus is trapped inside the sheet while open
  • Pressing Escape closes the sheet
  • The close button is rendered inside Sheet.Header in the normal document flow
  • Dialog - Centered modal dialog for critical confirmations
  • Button - Use as trigger and action buttons