WebberUI

Drawer

從畫面邊緣滑入的抽屜面板,支援四向、遮罩點擊關閉,並可單軸拖曳滑走關閉。

載入預覽⋯

Playground

即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。

<Drawer />

安裝

npx shadcn@latest add https://webberui.com/r/drawer.json

或在 components.json 設定 registries 後,改用 @webberui/drawer 安裝。

安裝依賴後,從 registry JSON(/r/drawer.jsonfiles[0].content)複製 drawer.tsx 原始碼到你的 components/ui/ 目錄:

npm install motion lucide-react clsx tailwind-merge

使用

import {
  Drawer,
  DrawerTrigger,
  DrawerContent,
  DrawerClose,
} from "@/components/ui/drawer";

<Drawer>
  <DrawerTrigger>開啟選單</DrawerTrigger>

  <DrawerContent side="right" className="w-72">
    <div className="flex items-center justify-between border-b border-neutral-200 px-5 py-4 dark:border-neutral-800">
      <h2 className="text-base font-semibold">選單</h2>
      <DrawerClose />
    </div>
    <nav className="p-3">{/* 選項 */}</nav>
  </DrawerContent>
</Drawer>;

DrawerContentside 決定滑入方向("top" | "right" | "bottom" | "left",預設 "right")。面板從對應邊緣以 spring 滑入,點擊遮罩或按 Esc 即可關閉。

傳入 openonOpenChange 可切換為受控模式:

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

<Drawer open={open} onOpenChange={setOpen}>
  {/* ... */}
</Drawer>;

Props

Drawer

Prop型別預設值說明
childrenReact.ReactNode內容,需包含 DrawerTriggerDrawerContent
openboolean受控模式的開啟狀態,不傳則由元件內部管理
onOpenChange(open: boolean) => void開啟狀態變更時的回呼(受控與非受控皆會觸發)

DrawerTrigger

Prop型別預設值說明
childrenReact.ReactNode觸發鈕內容
classNamestring追加到觸發鈕的 className

DrawerContent

Prop型別預設值說明
side"top" | "right" | "bottom" | "left""right"抽屜滑入的方向
classNamestring追加到面板容器的 className
childrenReact.ReactNode面板內容

DrawerClose

Prop型別預設值說明
childrenReact.ReactNodelucide-react X 圖示自訂按鈕內容
classNamestring追加到關閉按鈕的 className

細節

  • 四向滑入side 對應面板貼齊的邊緣與初始離場位移。左右向為滿高側欄(w-80 max-w-[85vw]),上下向為滿寬橫幅(max-h-[85vh]),皆可用 className 覆寫尺寸。
  • 拖曳關閉:面板以單軸 drag 跟手,只在「關閉方向」放開約束、開啟方向以彈性阻尼回彈。放開時若關閉方向的位移超過 80px 或速度超過 500px/s 即關閉,AnimatePresenceexit 從當前拖曳位置接續滑出;未達閾值則由 dragSnapToOrigin 自動彈回原位。
  • Portal 到 body:面板與遮罩經 createPortal 渲染到 document.body,避免祖先的 overflow 裁切或 transform 建立 containing block 影響 fixed 定位。
  • spring 滑入:入場使用 spring(stiffness: 380, damping: 40),與拖曳彈回共用同一組 spring,手勢與程式動畫的落點手感一致。
  • 受控模式:傳入 open 即切換為受控,元件不再改動內部狀態;onOpenChange 在受控與非受控下都會觸發,可用來監聽開關事件。
  • 可調校點:切換色的過渡時長取用 var(--wb-duration-fast, 200ms),未定義時回退 200ms。

可及性

  • 面板帶 role="dialog"aria-modal="true";開啟時焦點移入面板(tabIndex={-1}),關閉後焦點歸還給觸發鈕
  • 觸發鈕為原生 <button>,帶 aria-haspopup="dialog"aria-expanded 狀態,開啟時以 aria-controls 連結面板
  • 按 Esc 或點擊遮罩皆可關閉;開啟期間 body 設為 overflow: hidden 鎖住背景捲動,關閉時恢復原值
  • 使用者系統開啟「減少動態效果」時,滑入與拖曳退化為快速淡入淡出,不產生任何位移感
  • 元件走輕量路線,未內建 focus trap;若面板內有多個互動元素且需要完整的鍵盤焦點循環,建議自行搭配 focus trap 方案

On this page