導航

應用選單列

桌面應用式頂部選單列:開啟一個選單後 hover 相鄰項即直接切換,面板滑動到新位置而非關開,方向鍵完整巡覽。

這是 WebberUI Pro 元件

下方的安裝指令需要授權才能執行,未授權時會回 401。

怎麼安裝 Pro 元件 →查看方案 →

像桌面應用程式頂端那條「檔案/編輯/檢視」選單列。點開任一選單後,指標滑到相鄰的選單名稱就直接切換,不必再點;切換時不是舊面板關掉、新面板重開,而是同一個面板以彈簧動畫滑到新位置、大小跟著變,內容交叉淡接。項目層與下拉選單同款:一般項目、核取、單選、子選單、群組標題、分隔線與快捷鍵標示都有,鍵盤可用 ←/→ 在選單間移動、↑/↓ 巡覽項目。

把這個效果裝進你的專案

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

npx webberui@latest add "https://webberui.com/r/menubar.json?t=<安裝 token>"

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

Playground

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

100
500
150
編輯中的呼叫預設屬性
<Menubar/>

完整範例包含預覽的排版與資料。先安裝元件,再把範例檔貼入你的專案。

安裝

npx webberui@latest add "https://webberui.com/r/menubar.json?t=<安裝 token>"

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

使用

import { Menubar } from "@/components/ui/menubar";

const [lineNumbers, setLineNumbers] = React.useState(true);
const [fontSize, setFontSize] = React.useState("md");

<Menubar>
  <Menubar.Menu value="file">
    <Menubar.Trigger>檔案</Menubar.Trigger>
    <Menubar.Content>
      <Menubar.Item onSelect={() => console.log("新增")}>
        新增
        <Menubar.Shortcut>⌘N</Menubar.Shortcut>
      </Menubar.Item>
      <Menubar.Sub>
        <Menubar.SubTrigger>最近開啟</Menubar.SubTrigger>
        <Menubar.SubContent>
          <Menubar.Item>週會記錄.md</Menubar.Item>
          <Menubar.Item>旅行清單.md</Menubar.Item>
        </Menubar.SubContent>
      </Menubar.Sub>
      <Menubar.Separator />
      <Menubar.Item>匯出為 PDF</Menubar.Item>
    </Menubar.Content>
  </Menubar.Menu>
  <Menubar.Menu value="view">
    <Menubar.Trigger>檢視</Menubar.Trigger>
    <Menubar.Content>
      <Menubar.CheckboxItem checked={lineNumbers} onCheckedChange={setLineNumbers}>
        顯示行號
      </Menubar.CheckboxItem>
      <Menubar.Separator />
      <Menubar.Label inset>字級</Menubar.Label>
      <Menubar.RadioGroup value={fontSize} onValueChange={setFontSize}>
        <Menubar.RadioItem value="sm">小</Menubar.RadioItem>
        <Menubar.RadioItem value="md">中</Menubar.RadioItem>
        <Menubar.RadioItem value="lg">大</Menubar.RadioItem>
      </Menubar.RadioGroup>
    </Menubar.Content>
  </Menubar.Menu>
</Menubar>

Props

Prop型別預設值說明
valuestring—受控:目前開啟的 Menu 的 value,'' 表示全部關閉
defaultValuestring''非受控模式的初始開啟 Menu
onValueChange(value: string) => void—開啟的 Menu 變動時回呼(全關時傳 '')
loopbooleantrue方向鍵到頭尾時是否循環(Trigger 之間與選單項目之間都適用)
durationnumber100開關與內容交叉淡接的動畫時長(毫秒)
switchStiffnessnumber500切換選單時面板滑動的彈簧剛度
switchDampingnumber40切換選單時面板滑動的彈簧阻尼
subDelaynumber150指標停在子選單項目上多久後展開(毫秒)
classNamestring—透傳到選單列根元素
欄位型別預設值說明
valuestring—這個選單的唯一值(必填),用於 value/onValueChange
欄位型別預設值說明
disabledbooleanfalse停用:無法開啟,左右鍵巡覽時跳過
classNamestring—透傳到觸發鈕;其餘 button 屬性也會透傳
欄位型別預設值說明
classNamestring—透傳到選單面板(例如 min-w-56 調整最小寬度)
欄位型別預設值說明
onSelect() => void—選取時回呼(點擊、Enter 或 Space)
disabledbooleanfalse停用:無法選取,鍵盤巡覽時跳過
insetbooleanfalse左側留出與核取項目對齊的 icon 空間
textValuestring—typeahead 比對用文字;預設取項目的文字內容
closeOnSelectbooleantrue選取後是否關閉選單
classNamestring—透傳到項目
欄位型別預設值說明
checkedboolean—受控的勾選狀態
defaultCheckedbooleanfalse非受控模式的初始勾選狀態
onCheckedChange(checked: boolean) => void—勾選狀態變動時回呼
onSelect() => void—選取時回呼
disabledbooleanfalse停用
textValuestring—typeahead 比對用文字
closeOnSelectbooleanfalse選取後是否關閉選單(核取項目預設不關閉)
classNamestring—透傳到項目
欄位型別預設值說明
valuestring—受控的選中值
defaultValuestring—非受控模式的初始選中值
onValueChange(value: string) => void—選中值變動時回呼
classNamestring—透傳到群組容器
欄位型別預設值說明
valuestring—這個選項代表的值(必填)
onSelect() => void—選取時回呼
disabledbooleanfalse停用
textValuestring—typeahead 比對用文字
closeOnSelectbooleanfalse選取後是否關閉選單(單選項目預設不關閉)
classNamestring—透傳到項目
欄位型別預設值說明
openboolean—受控的子選單開啟狀態
defaultOpenbooleanfalse非受控模式的初始開啟狀態
onOpenChange(open: boolean) => void—子選單開啟狀態變動時回呼
欄位型別預設值說明
disabledbooleanfalse停用
insetbooleanfalse左側留出與核取項目對齊的 icon 空間
textValuestring—typeahead 比對用文字
classNamestring—透傳到項目
欄位型別預設值說明
sideOffsetnumber-4與 SubTrigger 的距離(px),負值讓子選單稍微疊上父選單
alignOffsetnumber-5沿交叉軸的偏移(px),預設讓第一項與 SubTrigger 對齊
collisionPaddingnumber8與視窗邊緣保持的最小距離(px)
classNamestring—透傳到子選單面板

Label/Group/Separator/Shortcut

欄位型別預設值說明
Label.insetbooleanfalse群組標題(非互動);inset 時與核取項目文字對齊
Group——以 role="group" 包住一組項目
Separator——role="separator" 的細分隔線
Shortcut——靠右的灰色等寬小字;只是標示,實際快捷鍵由你自己綁定

所有子元件都接受 className,以 cn() 併入。

細節

  • 切換行為:沒有選單開著時,要點擊 Trigger 才開啟;只要有一個開著,指標移入其他 Trigger 就立即切換,沒有延遲。再點一次目前開著的 Trigger 會關閉。
  • 只有一個面板容器:切換時不播放「舊面板退場+新面板進場」,而是同一個容器以彈簧(switchStiffness/switchDamping)把位置與寬高從舊錨點補間到新 Trigger 下方,內容以 duration 交叉淡接。只有從全關到開啟、或開啟到全關時,才播放淡入+從 95% 放大+向下滑入 8px 的進出場。
  • 定位:面板以 position: fixed 掛到 body,固定在 Trigger 下方靠左、間距 4px;下方放不下且上方空間較大時翻到上方,左右會推回視窗內並保留 8px。視窗縮放、任何祖先捲動、Trigger 或面板尺寸變化都以 requestAnimationFrame 節流重算,這類重算直接到位、不走彈簧,避免面板落後於錨點。
  • 動畫時長同時寫入 --wb-menubar-duration,面板內所有 CSS 過渡都讀這個變數,可在全域覆寫。
  • 子選單:停留 subDelay 毫秒後展開,以 SubTrigger 為錨點在右側展開(放不下時翻到左側);指標斜向移往子選單時,以「離開點+子選單兩角」構成的安全三角形判斷,途中掠過其他項目不會誤關。
  • typeahead:500ms 內連續輸入的字元累加成前綴比對 textValue(預設取項目文字、略過快捷鍵);中文以首字比對。
  • 點擊選單列與所有面板之外會關閉選單,焦點交給被點的元素。

可及性

  • 根元素為 role="menubar"、aria-orientation="horizontal";Trigger 為 role="menuitem",帶 aria-haspopup="menu"、aria-expanded 與 aria-controls
  • Trigger 之間採 roving tabindex:整條選單列只有一個 Tab 停駐點,←/→ 在 Trigger 間移動(loop 控制是否循環),Home/End 跳到頭尾
  • 有選單開著時按 ←/→(焦點在面板內且不在 SubTrigger 上),會切換到相鄰選單並把焦點放進新選單第一項
  • Trigger 上 ↓/Enter/Space 開啟並聚焦第一項、↑ 開啟並聚焦最後一項;面板內 ↑↓ 在非停用項間循環、Home/End 跳頭尾、Enter/Space 選取、Escape 關閉並回到 Trigger、Tab 關閉並讓焦點自然離開
  • 面板為 role="menu"、aria-orientation="vertical",項目依類型使用 menuitem、menuitemcheckbox、menuitemradio,核取與單選項帶 aria-checked;停用項目帶 aria-disabled 並在巡覽時跳過;快捷鍵標示對輔助科技隱藏
  • 子選單以 → 或 Enter 進入、← 或 Escape 返回 SubTrigger
  • typeahead 與 Enter 在中文等輸入法組字中(isComposing 或 keyCode 229)不觸發
  • 使用者系統開啟「減少動態效果」時,面板只保留淡入淡出(時長不變),不縮放、不位移;切換選單時面板直接跳到新位置,高亮列與單選圓點也直接到位