Drawer
beui/drawerFreeComponent
Side panel that slides in from the left or right with a spring, backdrop blur, body scroll lock and esc-to-close.
Install it
npx shadcn@latest add https://beui.dev/r/drawer.jsonSource
1"use client";2// beui.dev/components/motion/drawer34import { AnimatePresence, motion, useReducedMotion } from "motion/react";5import { useEffect, type ReactNode } from "react";6import { EASE_OUT, SPRING_PANEL } from "@/lib/ease";7import { cn } from "@/lib/utils";89export interface DrawerProps {10 open: boolean;11 onOpenChange: (open: boolean) => void;12 side?: "left" | "right";13 children: ReactNode;14 /** Class for the panel surface. */15 className?: string;16 /** Class for the backdrop. */17 backdropClassName?: string;18 ariaLabel?: string;19 /** Close when the backdrop is clicked. Default true. */20 dismissable?: boolean;21}2223export function Drawer({24 open,25 onOpenChange,26 side = "right",27 children,28 className,29 backdropClassName,30 ariaLabel,31 dismissable = true,32}: DrawerProps) {33 const reduce = useReducedMotion();3435 useEffect(() => {36 if (!open) return;37 const onKey = (e: KeyboardEvent) => {38 if (e.key === "Escape") onOpenChange(false);39 };40 window.addEventListener("keydown", onKey);41 const prevOverflow = document.body.style.overflow;42 document.body.style.overflow = "hidden";43 return () => {44 window.removeEventListener("keydown", onKey);45 document.body.style.overflow = prevOverflow;46 };47 }, [open, onOpenChange]);4849 const offscreen = side === "right" ? "100%" : "-100%";5051 return (52 <AnimatePresence>53 {open ? (54 <div className="fixed inset-0 z-50">55 <motion.button56 type="button"57 aria-label="Close"58 tabIndex={dismissable ? 0 : -1}59 onClick={() => dismissable && onOpenChange(false)}60 initial={{ opacity: 0 }}61 animate={{ opacity: 1 }}62 exit={{ opacity: 0 }}63 transition={{ duration: 0.25, ease: EASE_OUT }}64 className={cn(65 "absolute inset-0 h-full w-full cursor-default bg-black/40 backdrop-blur-sm",66 backdropClassName,67 )}68 />69 <motion.aside70 role="dialog"71 aria-modal="true"72 aria-label={ariaLabel}73 initial={reduce ? { opacity: 0 } : { x: offscreen }}74 animate={reduce ? { opacity: 1 } : { x: 0 }}75 exit={reduce ? { opacity: 0 } : { x: offscreen }}76 transition={reduce ? { duration: 0.2, ease: EASE_OUT } : SPRING_PANEL}77 className={cn(78 "absolute inset-y-0 flex w-80 max-w-[85vw] flex-col bg-background shadow-2xl",79// … truncated
What it pulls in
npm packages
Files it writes
More from beui
All 104 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Action Swap Bluraction-swap-blur | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Cascadeaction-swap-cascade | beui | Components | Free | 3 deps · 4 files | |
| Action Swap Rollaction-swap-roll | beui | Components | Free | 3 deps · 4 files | |
| Agent Activityagent-activity | beui | Components | Free | 4 deps · 9 files | |
| Agent Loading States Agent Progressagent-progress | beui | Components | Free | 3 deps · 3 files | |
| AI Sidebarai-sidebar | beui | Components | Free | 4 deps · 5 files | |
| Animated Badgeanimated-badge | beui | Components | Free | 4 deps · 3 files | |
| Number Animation Animated Numberanimated-number | beui | Components | Free | 3 deps · 3 files |
