UIUpdated April 28, 2026

Sheet

Slide-over panel built on Radix Dialog. Use it for side panels, filters, navigation, and contextual actions.

UISheet

Side workflows without leaving contextLink to section

The Sheet component is a slide-over panel used for side workflows, filters, navigation, and contextual editing.

Use it for:

  • advanced filters
  • mobile navigation
  • side editing panels
  • detail panels
  • contextual settings
  • secondary workflows that should preserve page context

Sheet is built on Radix Dialog and styled with PyColors semantic tokens such as bg-card, border-border, and text-foreground.

Core idea

Sheet keeps the user in context while exposing a larger secondary workflow.

ImportLink to section

sheet-import.tsx
import { Sheet } from "@pycolors/ui";

Basic usageLink to section

Use Sheet for a side panel that contains a focused but larger workflow than a Dialog.

profile-sheet.tsx
"use client";

import {
  Button,
  Input,
  Sheet,
  SheetTrigger,
  SheetClose,
  SheetContent,
  SheetHeader,
  SheetFooter,
  SheetTitle,
  SheetDescription,
} from "@pycolors/ui";

export function ProfileSheet() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="outline">Open sheet</Button>
      </SheetTrigger>

      <SheetContent side="right" className="w-[380px] sm:w-[420px]">
        <SheetHeader>
          <SheetTitle>Edit profile</SheetTitle>
          <SheetDescription>
            Update your account details. Changes are saved on submit.
          </SheetDescription>
        </SheetHeader>

        <div className="mt-6 grid gap-3">
          <Input label="Name" placeholder="Patrice" />
          <Input label="Email" placeholder="you@domain.com" />
          <Input label="Company" placeholder="PyColors" autoComplete="organization" />
        </div>

        <SheetFooter className="mt-6">
          <SheetClose asChild>
            <Button variant="secondary">Cancel</Button>
          </SheetClose>
          <Button>Save</Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}

Trigger rule

Prefer SheetTrigger asChild so the trigger keeps the semantics of the element you pass, such as a real Button.

When to use SheetLink to section

Use Sheet when the user needs more space than a menu, but should keep page context.

Filters

Use for advanced filters without crowding the toolbar.

Side editing

Use for editing records while keeping the parent page visible.

Mobile navigation

Use a left sheet for mobile menus and app navigation.

SidesLink to section

Sheets support four placement options through the side prop.

Use the placement to match the mental model of the workflow.

sheet-sides.tsx
import {
  Button,
  Sheet,
  SheetTrigger,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetDescription,
} from "@pycolors/ui";

export function SheetSides() {
  return (
    <div className="flex flex-wrap gap-2">
      <Sheet>
        <SheetTrigger asChild>
          <Button variant="outline">Right</Button>
        </SheetTrigger>
        <SheetContent side="right">
          <SheetHeader>
            <SheetTitle>Right sheet</SheetTitle>
            <SheetDescription>
              Default placement for editing and details.
            </SheetDescription>
          </SheetHeader>
        </SheetContent>
      </Sheet>

      <Sheet>
        <SheetTrigger asChild>
          <Button variant="outline">Left</Button>
        </SheetTrigger>
        <SheetContent side="left">
          <SheetHeader>
            <SheetTitle>Left sheet</SheetTitle>
            <SheetDescription>
              Recommended for navigation.
            </SheetDescription>
          </SheetHeader>
        </SheetContent>
      </Sheet>
    </div>
  );
}

Placement guidanceLink to section

SideBest for
rightEditing, details, contextual panels
leftNavigation, app menu, mobile sidebar
topGlobal filters, announcements, compact controls
bottomMobile-first actions, quick controls

Placement rule

Use right for editing, left for navigation, and bottom for mobile-first action panels.

Close behaviorLink to section

SheetContent includes a close button. Use SheetClose for explicit footer actions.

sheet-close-actions.tsx
import {
  Button,
  Sheet,
  SheetTrigger,
  SheetContent,
  SheetHeader,
  SheetTitle,
  SheetDescription,
  SheetClose,
} from "@pycolors/ui";

export function SheetCloseActions() {
  return (
    <Sheet>
      <SheetTrigger asChild>
        <Button variant="outline">Open</Button>
      </SheetTrigger>

      <SheetContent>
        <SheetHeader>
          <SheetTitle>Confirm</SheetTitle>
          <SheetDescription>
            Close with the button, the close control, or Escape.
          </SheetDescription>
        </SheetHeader>

        <div className="mt-6 flex gap-2">
          <SheetClose asChild>
            <Button variant="secondary">Cancel</Button>
          </SheetClose>
          <SheetClose asChild>
            <Button>Done</Button>
          </SheetClose>
        </div>
      </SheetContent>
    </Sheet>
  );
}

Usage patternsLink to section

Choose the right sideLink to section

Pick the placement based on the workflow: right for details, left for navigation, bottom for mobile actions.

Keep the page context visibleLink to section

A sheet should extend the page, not replace it. Avoid using it for flows that need a full page.

Provide title and descriptionLink to section

Use SheetTitle and SheetDescription so users understand the purpose of the panel.

Use one primary actionLink to section

Most sheets should have one primary action and one secondary close or cancel action.

Handle scroll intentionallyLink to section

Avoid nested scroll containers. Prefer one clear scrollable region inside the sheet.

Sheet vs Dialog vs Dropdown MenuLink to section

SituationUse
Advanced filtersSheet
Side editing panelSheet
Mobile navigationSheet
Record details panelSheet
Short destructive confirmationDialog
Small contextual action listDropdownMenu
Full multi-step workflowPage

Decision rule

Sheet is for side workflows. Dialog is for focused decisions. Dropdown Menu is for compact choices.

APILink to section

ComponentsLink to section

ComponentDescription
SheetRoot container
SheetTriggerTrigger element, usually with asChild
SheetCloseClose control, usually wrapping a Button
SheetContentSlide-over panel surface
SheetHeaderTitle and description stack helper
SheetFooterAction row helper
SheetTitleAccessible sheet title
SheetDescriptionSupporting text

SheetContent propsLink to section

PropTypeDefaultDescription
sideSheetSide"right"Placement of the panel
classNamestringAdditional Tailwind classes
...propsDialogPrimitive.Content propsRadix Dialog Content props

Sheet, SheetTrigger, and SheetClose are re-exports of Radix Dialog primitives and accept their native props.

TypeScript typesLink to section

sheet-types.ts
export type SheetSide = "top" | "bottom" | "left" | "right";

export interface SheetContentProps
  extends React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> {
  side?: SheetSide;
}

AccessibilityLink to section

Sheet is built on Radix Dialog primitives.

That means:

  • focus is trapped while open
  • focus returns to the trigger on close
  • Escape closes the sheet by default
  • screen readers receive dialog semantics
  • SheetTitle provides the accessible name

Guidelines:

  • use SheetTrigger asChild with a semantic trigger
  • include a clear SheetTitle
  • include a useful SheetDescription
  • avoid using Sheet for destructive confirmations
  • avoid nested sheets
  • avoid long multi-step flows inside a sheet

Accessibility rule

A sheet still behaves like a dialog. It needs clear labeling, focus management, and a bounded task.

Prefer / avoidLink to section

Prefer

  • right sheets for editing and details
  • left sheets for navigation
  • clear title and description
  • one primary footer action
  • one intentional scroll region

Avoid

  • destructive confirmations that should be dialogs
  • full-page workflows squeezed into a panel
  • nested sheets
  • multiple competing primary actions
  • unclear scrolling with nested containers

Product copy guidelinesLink to section

Sheet copy should tell users what the panel does and what happens next.

Filter projects

Narrow results by status, owner, date, and plan.

Edit profile

Update account details. Changes are saved when you submit.

Navigation

Move between product areas without losing your current context.

Common questionsLink to section