導航

Dock

macOS 風格放大 dock:圖示依與游標的水平距離平滑放大,hover 浮出標籤。

把這個效果裝進你的專案

在專案資料夾執行指令,CLI 會加入原始碼與依賴套件,再依下方使用範例引用元件。

npx webberui@latest add dock

還沒有專案,或安裝遇到問題?看快速開始 →

Dock 是用 React、Tailwind CSS 與 Motion 做的 macOS 風格 dock 選單(放大工具列/magnification dock)元件:滑鼠靠近時,圖示依水平距離由 spring 平滑放大,hover 或鍵盤聚焦時在上方浮出標籤。

Playground

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

64
40
140
編輯中的呼叫預設屬性
<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型別預設值說明
magnificationnumber64游標最接近時的圖示尺寸(px)
baseSizenumber40靜止時的圖示尺寸(px)
distancenumber140放大影響半徑(px):游標與圖示中心的水平距離在此範圍內才會放大
classNamestring—附加到 dock 容器的 class
childrenReact.ReactNode—直接放入 DockItem 子元件

DockItem

Prop型別預設值說明
labelstring—圖示標籤:hover 或鍵盤 focus 時顯示於上方,同時作為 aria-label
onClickReact.MouseEventHandler—點擊事件(button 與連結皆適用)
hrefstring—提供時渲染為 <a> 連結,否則為 <button>
childrenReact.ReactNode—圖示內容:任意 SVG 或元素,會自動填滿圖示區並隨放大等比縮放
classNamestring—附加到單一圖示按鈕的 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 結構不變,連結與按鈕功能照常。