Dock
macOS 風格放大 dock:圖示依與游標的水平距離平滑放大,hover 浮出標籤。
把這個效果裝進你的專案
在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。
npx webberui@latest add dockDock 是用 React、Tailwind CSS 與 Motion 做的 macOS 風格 dock 選單(放大工具列/magnification dock)元件:滑鼠靠近時,圖示依水平距離由 spring 平滑放大,hover 或鍵盤聚焦時在上方浮出標籤。
Playground
即時調整 props、程式碼片段同步更新——直接試出你要的樣子再複製。
<Dock/>
完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。
適用情境
- 作品集或個人網站底部的固定導覽列,放社群連結與主要頁面。
- 編輯器、白板類應用的工具列,例如畫筆、選取、文字、匯出。
- 行動版優先的網站在桌機上的快捷列;觸控時會維持一般尺寸的按鈕列。
- 不適合:項目超過十個左右或需要文字標籤常駐的主選單,改用一般的導覽列或側邊欄比較好掃讀。
安裝
npx webberui@latest add https://webberui.com/r/dock.json安裝時會一併寫入 --wb-duration-fast CSS 變數到你的全域樣式。
使用
import { Dock, DockItem } from "@/components/ui/dock";
import { Home, Search, Settings } from "lucide-react";
<Dock>
<DockItem label="首頁" href="/">
<Home />
</DockItem>
<DockItem label="搜尋" onClick={() => console.log("search")}>
<Search />
</DockItem>
<DockItem label="設定" href="/settings">
<Settings />
</DockItem>
</Dock>範例
固定在畫面底部
在 className 加上定位 class,讓 dock 固定在視窗底部中央。
import { Dock, DockItem } from "@/components/ui/dock";
import { Home, FolderOpen, Mail } from "lucide-react";
export function BottomDock() {
return (
<Dock className="fixed bottom-6 left-1/2 z-50 -translate-x-1/2">
<DockItem label="首頁" href="/">
<Home />
</DockItem>
<DockItem label="作品" href="/projects">
<FolderOpen />
</DockItem>
<DockItem label="聯絡我" href="mailto:hello@example.com">
<Mail />
</DockItem>
</Dock>
);
}搭配 Next.js 用戶端導頁
href 會渲染成一般的 <a>。想走 Next.js 的用戶端路由,可以不給 href、改在 onClick 呼叫 router.push。
"use client";
import { useRouter } from "next/navigation";
import { Dock, DockItem } from "@/components/ui/dock";
import { LayoutDashboard, Settings } from "lucide-react";
export function AppDock() {
const router = useRouter();
return (
<Dock>
<DockItem label="總覽" onClick={() => router.push("/dashboard")}>
<LayoutDashboard />
</DockItem>
<DockItem label="設定" onClick={() => router.push("/settings")}>
<Settings />
</DockItem>
</Dock>
);
}調整放大幅度與影響範圍
baseSize 是靜止尺寸、magnification 是最大尺寸、distance 是游標影響的水平半徑;三者都以 px 計。
<Dock baseSize={48} magnification={80} distance={180}>
{/* DockItem… */}
</Dock>Props
Dock
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
magnification | number | 64 | 游標最接近時的圖示尺寸(px) |
baseSize | number | 40 | 靜止時的圖示尺寸(px) |
distance | number | 140 | 放大影響半徑(px):游標與圖示中心的水平距離在此範圍內才會放大 |
className | string | — | 附加到 dock 容器的 class |
children | React.ReactNode | — | 直接放入 DockItem 子元件 |
DockItem
| Prop | 型別 | 預設值 | 說明 |
|---|---|---|---|
label | string | — | 圖示標籤:hover 或鍵盤 focus 時顯示於上方,同時作為 aria-label |
onClick | React.MouseEventHandler | — | 點擊事件(button 與連結皆適用) |
href | string | — | 提供時渲染為 <a> 連結,否則為 <button> |
children | React.ReactNode | — | 圖示內容:任意 SVG 或元素,會自動填滿圖示區並隨放大等比縮放 |
className | string | — | 附加到單一圖示按鈕的 class |
細節
- 共享 mouseX:容器 pointermove 更新共享的游標 X 座標(
MotionValue),離開時設為Infinity;每個DockItem以useTransform把「與游標的水平距離」映射成尺寸區間,再經useSpring平滑,形成經典 macOS 放大波形 - dock 本體不跳動:容器高度固定為
baseSize+ 留白、圖示底部對齊,放大時向上溢出 - tooltip 標籤:hover 單一圖示時以
AnimatePresence浮出上方小卡;標籤同時是aria-label,小卡本身對輔助科技隱藏、不重複朗讀 - 鍵盤可及性:
DockItem是原生<button>(有href時為<a>),Tab 可逐一聚焦;focus-visible時同樣放大到magnification並顯示標籤 - 觸控裝置自動退化:僅回應滑鼠的 pointer 事件(
pointerType === "mouse"),觸控時就是一列等尺寸的普通按鈕 - 使用者系統開啟「減少動態效果」時停用放大與標籤位移動畫,DOM 結構完全一致、功能不受影響
- 元件本體不依賴任何 icon 庫,
children放什麼 SVG 都會自動撐滿圖示區
常見問題
可以在 Next.js App Router 使用嗎?
可以。檔案開頭已有 "use client",在 Server Component 頁面中照常 import。若要用 useRouter 導頁,呼叫它的那個元件本身也需要是 Client Component。
一定要用 lucide-react 嗎?
不用。元件本體不依賴任何 icon 庫,DockItem 的 children 放任何 SVG 都會自動填滿圖示區並跟著放大。上方使用範例用的是 lucide-react,若要照抄需要另外安裝。
手機上會放大嗎?
不會。放大只回應滑鼠的 pointer 事件,觸控時就是一列等尺寸的按鈕,點擊照常運作。
鍵盤和螢幕閱讀器可以操作嗎?
DockItem 是原生 <button>,有 href 時是 <a>,可以用 Tab 逐一聚焦;鍵盤聚焦時會放大並顯示標籤。label 同時作為 aria-label,浮出的標籤小卡對輔助科技隱藏,不會重複朗讀。
開啟「減少動態效果」會怎樣?
放大效果與標籤位移動畫會停用,DOM 結構不變,連結與按鈕功能照常。