WebberUI

Mega Menu

A large dropdown navigation menu whose panel height morphs smoothly to fit as you switch items, with hover and keyboard support.

This is a WebberUI Pro component

Free during the launch campaign: sign up or sign in, then hit “Copy install command” in the preview above and it installs straight away — no payment, no credit card. The command below returns 401 while you are signed out.

How to install Pro components →See the plans →

Loading preview…
npx shadcn@latest add "https://webberui.com/r/mega-menu.json?t=<install token>"

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

150
<MegaMenu />

Installation

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

Or, once registries are configured in components.json, install it as @webberui/mega-menu.

Usage

Assemble it from compound components. Every MegaMenuItem needs a unique value and contains one MegaMenuTrigger and one MegaMenuContent.

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

<MegaMenu align="center">
  <MegaMenuList label="Main navigation">
    <MegaMenuItem value="products">
      <MegaMenuTrigger>Products</MegaMenuTrigger>
      <MegaMenuContent>{/* Large panel content */}</MegaMenuContent>
    </MegaMenuItem>

    <MegaMenuItem value="resources">
      <MegaMenuTrigger>Resources</MegaMenuTrigger>
      <MegaMenuContent>{/* Another set of content, possibly a different height */}</MegaMenuContent>
    </MegaMenuItem>
  </MegaMenuList>
</MegaMenu>

When panels for different items have different sizes, the container morphs its height and width automatically as you switch, instead of jumping instantly.

controlled mode

Pass value (the expanded item's value, or null for collapsed) and onValueChange to take over the open state; when omitted, the component manages it internally.

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

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

Props

MegaMenu

PropTypeDefaultDescription
valuestring | nullThe expanded item in controlled mode; null means collapsed
defaultValuestring | nullnullInitially expanded item in uncontrolled mode
onValueChange(value: string | null) => voidCallback fired when the expanded item changes
align"start" | "center" | "end""start"Horizontal alignment of the panel relative to the navigation bar
closeDelaynumber150Milliseconds to wait before closing after the mouse leaves

MegaMenuList

PropTypeDefaultDescription
labelstring"Main navigation"Accessible name for the navigation bar (nav)
classNamestringAppended to the navigation bar container's className

MegaMenuItem

PropTypeDefaultDescription
valuestringUnique identifier for this item (required)
classNamestringAppended to the item container's (li) className

MegaMenuTrigger / MegaMenuContent

PropTypeDefaultDescription
childrenReactNodeTrigger content / panel content
classNamestringAppended className (for Content it applies to the content area)

How it works

  • A single morphing container: each MegaMenuContent registers its content into a shared collection at render time, and an internal Viewport renders them all in one container carrying layout; when you switch items, popLayout takes the exiting panel out of the layout flow so the container immediately measures the new content and tweens its height.
  • Hover intent: moving the mouse onto a trigger expands it, and leaving the navigation bar only closes it after closeDelay, which leaves a buffer for moving onto the panel; moving back in cancels the close.
  • The panel sits right under the navigation bar: it is an absolutely positioned child inside the nav rather than a portal, so moving the mouse between the trigger and the panel never closes it by accident.

Accessibility

  • The trigger is a native button carrying aria-haspopup, aria-expanded, and — while expanded — aria-controls pointing at the panel region (role="region").
  • Keyboard operation: Enter / Space toggles expansion; ArrowLeft / ArrowRight plus Home / End move between triggers (switching the panel too when one is already open); ArrowDown expands and moves focus into the panel; Escape closes it and focus returns to the trigger.
  • Clicking outside the navigation bar closes the panel.
  • When the user has "reduce motion" enabled at the system level, the height morph along with the displacement and scaling are disabled, leaving only a brief fade in and out.

On this page