WebberUI

Slide Over Panel

非模態的窄版浮動面板,可拖曳磁吸至左右任一側,快甩即收合為邊緣把手,全程彈簧跟手。

載入預覽⋯

Playground

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

300
<SlideOverPanel />

安裝

npx shadcn@latest add https://webberui.com/r/slide-over-panel.json

或在 components.json 設定 registries 後,改用 @webberui/slide-over-panel 安裝。

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

npm install motion clsx tailwind-merge lucide-react

使用

面板以 absolute 定位,anchor="container"(預設)時會貼齊最近的定位祖先,請確保外層容器為 position: relative

import { SlideOverPanel } from "@/components/ui/slide-over-panel";

<div className="relative h-[480px] overflow-hidden">
  {/* 你的主要內容 */}
  <SlideOverPanel title="近期動態">
    <p>面板內容…</p>
  </SlideOverPanel>
</div>

若要讓面板浮於整個視口,改用 anchor="viewport"(採 fixed 定位,不需定位祖先)。

Props

Prop型別預設值說明
childrenReact.ReactNode面板內容
titleReact.ReactNode面板抬頭標題,同時作為無障礙標籤來源
side"left" | "right"受控貼齊側
defaultSide"left" | "right""right"非受控預設貼齊側
onSideChange(side) => void貼齊側變更回呼
collapsedboolean受控收合狀態
defaultCollapsedbooleanfalse非受控預設收合狀態
onCollapsedChange(collapsed) => void收合狀態變更回呼
panelWidthnumber300面板本體寬度(px,不含把手)
anchor"container" | "viewport""container"定位基準
labelstring無障礙標籤,未提供時回退到 title
classNamestring追加到面板本體的 className

細節

  • 磁吸貼側:拖放後依面板中心落在容器左右哪一半,彈簧吸附到該側並展開。
  • 快甩收合:放開時水平速度超過門檻(600 px/s),即朝甩動方向收合為邊緣把手;反向拉出把手則重新展開。
  • 全程跟手:拖曳、回彈、磁吸、收合皆走同一組 spring,落點俐落不生硬。
  • 受控雙軸sidecollapsed 皆支援受控/非受控雙模式,可各自獨立控制。

可及性

  • 面板為 role="region",以 titlelabel 作為 aria-label
  • 邊緣把手為原生 buttonEnter / Space 切換收合, / 磁吸至左右側並展開,補足拖曳無法用鍵盤操作的缺口。
  • 把手以 aria-expanded 反映展開狀態;收合時面板本體帶 aria-hidden 並停用互動。
  • 面板為非模態,不鎖捲動、不攔截底層內容的互動(pointer-events 僅作用於面板本身)。
  • 使用者系統開啟「減少動態效果」時,停用拖曳並改以瞬間定位取代彈簧位移。

On this page