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.json 的 files[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 | 型別 | 預設值 | 說明 |
|---|---|---|---|
children | React.ReactNode | — | 面板內容 |
title | React.ReactNode | — | 面板抬頭標題,同時作為無障礙標籤來源 |
side | "left" | "right" | — | 受控貼齊側 |
defaultSide | "left" | "right" | "right" | 非受控預設貼齊側 |
onSideChange | (side) => void | — | 貼齊側變更回呼 |
collapsed | boolean | — | 受控收合狀態 |
defaultCollapsed | boolean | false | 非受控預設收合狀態 |
onCollapsedChange | (collapsed) => void | — | 收合狀態變更回呼 |
panelWidth | number | 300 | 面板本體寬度(px,不含把手) |
anchor | "container" | "viewport" | "container" | 定位基準 |
label | string | — | 無障礙標籤,未提供時回退到 title |
className | string | — | 追加到面板本體的 className |
細節
- 磁吸貼側:拖放後依面板中心落在容器左右哪一半,彈簧吸附到該側並展開。
- 快甩收合:放開時水平速度超過門檻(600 px/s),即朝甩動方向收合為邊緣把手;反向拉出把手則重新展開。
- 全程跟手:拖曳、回彈、磁吸、收合皆走同一組 spring,落點俐落不生硬。
- 受控雙軸:
side與collapsed皆支援受控/非受控雙模式,可各自獨立控制。
可及性
- 面板為
role="region",以title或label作為aria-label。 - 邊緣把手為原生
button:Enter/Space切換收合,←/→磁吸至左右側並展開,補足拖曳無法用鍵盤操作的缺口。 - 把手以
aria-expanded反映展開狀態;收合時面板本體帶aria-hidden並停用互動。 - 面板為非模態,不鎖捲動、不攔截底層內容的互動(
pointer-events僅作用於面板本身)。 - 使用者系統開啟「減少動態效果」時,停用拖曳並改以瞬間定位取代彈簧位移。