導航

Mega Menu

大型下拉導覽選單,切換項目時面板高度自適應平滑 morph,支援懸停與鍵盤操作。

這是 WebberUI Pro 元件

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

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

把這個效果裝進你的專案

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

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

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

Mega Menu 是用 React、Tailwind CSS 與 Motion 做的大型下拉選單(mega menu)導覽元件:以 compound components 組合,滑鼠移入觸發鈕即展開,切換項目時同一個面板容器會依內容平滑調整高度與寬度。

Playground

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

150
編輯中的呼叫預設屬性
<MegaMenu/>

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

適用情境

  • SaaS 或企業官網頂部導覽,「產品」「解決方案」「資源」各自需要多欄連結。
  • 電商網站的商品分類選單,一個面板裡放子分類與主打圖片。
  • 文件站或開發者入口,把 API、SDK、教學分組呈現。
  • 不適合:行動版漢堡選單或全螢幕導覽,改用 Fullscreen Menu;項目少、不需要下拉面板時,可以看 Pill Nav。

安裝

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

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

使用

以 compound components 組合。每個 MegaMenuItem 需帶唯一的 value,並包含一個 MegaMenuTrigger 與一個 MegaMenuContent。

import {
  MegaMenu,
  MegaMenuList,
  MegaMenuItem,
  MegaMenuTrigger,
  MegaMenuContent,
} from "@/components/ui/mega-menu";

<MegaMenu align="center">
  <MegaMenuList label="主導覽">
    <MegaMenuItem value="products">
      <MegaMenuTrigger>產品</MegaMenuTrigger>
      <MegaMenuContent>{/* 大型面板內容 */}</MegaMenuContent>
    </MegaMenuItem>

    <MegaMenuItem value="resources">
      <MegaMenuTrigger>資源</MegaMenuTrigger>
      <MegaMenuContent>{/* 另一組內容,高度可不同 */}</MegaMenuContent>
    </MegaMenuItem>
  </MegaMenuList>
</MegaMenu>

不同項目的面板內容尺寸不同時,切換時容器會自動 morph 高度與寬度,而非瞬間跳動。

受控模式

傳入 value(展開的項目 value,null 為收合)與 onValueChange 即可接管開闔狀態;不傳則由元件內部管理。

const [open, setOpen] = useState<string | null>(null);

<MegaMenu value={open} onValueChange={setOpen}>
  {/* ... */}
</MegaMenu>

範例

多欄產品面板

MegaMenuContent 的內容可以是任何排版,這裡用兩欄連結加說明文字;className 會套用到面板內容區。

import {
  MegaMenu,
  MegaMenuList,
  MegaMenuItem,
  MegaMenuTrigger,
  MegaMenuContent,
} from "@/components/ui/mega-menu";

const products = [
  { href: "/analytics", title: "數據分析", desc: "即時查看流量與轉換" },
  { href: "/automation", title: "自動化流程", desc: "排程寄信與觸發條件" },
  { href: "/crm", title: "客戶管理", desc: "整合聯絡人與交易紀錄" },
  { href: "/integrations", title: "整合服務", desc: "串接常用的第三方工具" },
];

export function SiteNav() {
  return (
    <MegaMenu>
      <MegaMenuList label="主導覽">
        <MegaMenuItem value="products">
          <MegaMenuTrigger>產品</MegaMenuTrigger>
          <MegaMenuContent className="grid w-[32rem] grid-cols-2 gap-2">
            {products.map((p) => (
              <a key={p.href} href={p.href} className="rounded-lg p-3 hover:bg-neutral-100 dark:hover:bg-neutral-800">
                <p className="text-sm font-medium">{p.title}</p>
                <p className="text-xs text-neutral-500">{p.desc}</p>
              </a>
            ))}
          </MegaMenuContent>
        </MegaMenuItem>
        <MegaMenuItem value="pricing">
          <MegaMenuTrigger>方案</MegaMenuTrigger>
          <MegaMenuContent className="w-64">
            <a href="/pricing" className="block rounded-lg p-3 text-sm hover:bg-neutral-100 dark:hover:bg-neutral-800">比較所有方案</a>
          </MegaMenuContent>
        </MegaMenuItem>
      </MegaMenuList>
    </MegaMenu>
  );
}

點擊連結後收合

面板內的連結不會自動關閉選單。在 Next.js 用 Link 做用戶端跳頁時,可以改用受控模式,在點擊後把 value 設為 null。

"use client";

import * as React from "react";
import Link from "next/link";

export function DocsNav() {
  const [open, setOpen] = React.useState<string | null>(null);

  return (
    <MegaMenu value={open} onValueChange={setOpen} align="end">
      <MegaMenuList label="文件導覽">
        <MegaMenuItem value="guides">
          <MegaMenuTrigger>教學</MegaMenuTrigger>
          <MegaMenuContent className="flex w-56 flex-col">
            <Link href="/docs/quick-start" onClick={() => setOpen(null)}>快速開始</Link>
            <Link href="/docs/deploy" onClick={() => setOpen(null)}>部署到正式環境</Link>
          </MegaMenuContent>
        </MegaMenuItem>
      </MegaMenuList>
    </MegaMenu>
  );
}

調整關閉延遲

closeDelay 決定滑鼠離開後多久才收合;面板與觸發鈕距離較遠或使用者容易滑出時,可以拉長到 300 毫秒左右。

<MegaMenu align="center" closeDelay={300}>
  {/* ... */}
</MegaMenu>

Props

MegaMenu

Prop型別預設值說明
valuestring | null—受控模式的展開項目,null 為收合
defaultValuestring | nullnull非受控模式的初始展開項目
onValueChange(value: string | null) => void—展開項目變更時的回呼
align"start" | "center" | "end""start"面板相對導覽列的水平對齊
closeDelaynumber150滑鼠移出後延遲關閉的毫秒數

MegaMenuList

Prop型別預設值說明
labelstring"主導覽"導覽列(nav)的無障礙名稱
classNamestring—追加到導覽列容器的 className

MegaMenuItem

Prop型別預設值說明
valuestring—此項目的唯一識別(必填)
classNamestring—追加到項目容器(li)的 className

MegaMenuTrigger / MegaMenuContent

Prop型別預設值說明
childrenReactNode—觸發鈕內容 / 面板內容
classNamestring—追加的 className(Content 套用於內容區)

細節

  • 單一容器 morph:各 MegaMenuContent 於 render 時把內容登記到共享集合,由內部 Viewport 集中渲染於同一個帶 layout 的容器;切換項目時以 popLayout 讓離場面板脫離排版流,容器立即依新內容量測並補間高度。
  • 懸停意圖:滑鼠移入觸發鈕即展開,移出導覽列後延遲 closeDelay 才關閉,留出移動到面板的緩衝;再次移入會取消關閉。
  • 面板即在導覽列下方:面板為 nav 內的絕對定位子節點,不使用 portal,滑鼠在觸發鈕與面板之間移動不會誤觸關閉。

可及性

  • 觸發鈕為原生 button,帶 aria-haspopup、aria-expanded 與展開時的 aria-controls,指向面板區域(role="region")。
  • 鍵盤操作:Enter / Space 切換展開;ArrowLeft / ArrowRight 與 Home / End 於觸發鈕之間移動(面板已開時同步切換);ArrowDown 展開並將焦點移入面板;Escape 關閉並將焦點歸還觸發鈕。
  • 點擊導覽列以外區域會關閉面板。
  • 使用者系統開啟「減少動態效果」時,停用高度 morph 與位移縮放,僅保留短暫淡入淡出。

常見問題

可以在 Next.js App Router 使用嗎?

可以。原始碼開頭已有 "use client",在 Server Component 的 layout 或頁面直接 import 即可;面板內可以放 next/link。

觸控裝置上怎麼操作?

懸停展開只對滑鼠指標生效,觸控與觸控筆改以點擊觸發鈕開關。點擊導覽列以外的區域會關閉面板。

面板寬度怎麼控制?

面板容器是 w-max,最小 16rem、最大 min(90vw, 44rem),實際寬度由你的內容決定;在 MegaMenuContent 的 className 設定寬度或格線即可。用 align 決定面板靠左、置中或靠右對齊導覽列。

鍵盤操作支援哪些按鍵?

Enter/Space 切換展開,左右方向鍵與 Home/End 在觸發鈕之間移動,ArrowDown 展開並把焦點移入面板,Escape 關閉並把焦點還給觸發鈕。

減少動態效果時會怎樣?

系統開啟「減少動態效果」時,元件停用高度 morph 與位移縮放,只保留短暫的淡入淡出。