Components

Drawer

A props-driven side drawer with header, scrollable body, sticky footer, and four widths.

layout

Installation

npx cano-ui add drawer

Installs sheet automatically if missing.

Source

"use client"

import * as React from "react"

import { cn } from "@/lib/utils"
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
  SheetTrigger,
} from "@/components/ui/sheet"

export type DrawerSize = "sm" | "default" | "lg" | "xl"

export interface DrawerProps {
  /** Element that opens the drawer, rendered via Radix `asChild`. */
  trigger?: React.ReactNode
  title: string
  description?: string
  side?: "left" | "right"
  size?: DrawerSize
  /** Sticky footer slot, e.g. save/cancel actions. */
  footer?: React.ReactNode
  open?: boolean
  onOpenChange?: (open: boolean) => void
  className?: string
  children?: React.ReactNode
}

const sizeClasses: Record<DrawerSize, string> = {
  sm: "sm:max-w-sm",
  default: "sm:max-w-md",
  lg: "sm:max-w-lg",
  xl: "sm:max-w-xl",
}

export function Drawer({
  trigger,
  title,
  description,
  side = "right",
  size = "default",
  footer,
  open,
  onOpenChange,
  className,
  children,
}: DrawerProps) {
  return (
    <Sheet open={open} onOpenChange={onOpenChange}>
      {trigger ? <SheetTrigger asChild>{trigger}</SheetTrigger> : null}
      <SheetContent
        side={side}
        data-slot="drawer"
        className={cn("w-full gap-0", sizeClasses[size], className)}
      >
        <SheetHeader className="border-b">
          <SheetTitle>{title}</SheetTitle>
          {description ? (
            <SheetDescription>{description}</SheetDescription>
          ) : null}
        </SheetHeader>
        <div className="flex-1 overflow-y-auto p-4">{children}</div>
        {footer ? (
          <SheetFooter className="flex-row justify-end border-t">
            {footer}
          </SheetFooter>
        ) : null}
      </SheetContent>
    </Sheet>
  )
}

This exact file lands in your project at components/ui/drawer.tsx. It is yours to edit.