KQ-1284 · BRIDGE/MENU

Bridge Menu

A navigation bar with one mega-menu panel for every trigger: moving from one trigger to the next, the same panel slides across and resizes to the new content on springs.glide while that content crossfades in from the side the pointer came from, and a notch on the panel's edge and a pill behind the trigger move on springs.snap so they arrive first. A safe triangle from the last point on the open trigger to the panel's top edge (the bridge) holds the menu open while the pointer heads diagonally across other triggers, until it reaches the panel, leaves the triangle or rests, and bridge="show" draws it. The triggers are disclosure buttons in one tab stop: Left and Right move along the bar with the open panel following, Enter or Space opens, Down moves into the panel and Escape comes back to the trigger.

KQ-1284 · BRIDGE/MENU

menu closed · hover a trigger

Install

One command — the source lands in your repo. Or copy it from the Code tab.

$ pnpm dlx shadcn@latest add @kinetiq/bridge-menu

Props

items
BridgeMenuItem[]
default defaultBridgeMenuItems
The bar's items in order. An item with sections (and an optional feature card) or custom content has a panel; an item with only an href is a plain link in the bar.
value / defaultValue
string | null
default null
The open menu's id, or null when closed, controlled or initial.
onValueChange
(id: string | null) => void
default —
Fires from the hover, press or key that opened, switched or closed a menu.
onSelect
(link: BridgeMenuLink, itemId: string, event: React.MouseEvent) => void
default —
A link in a panel (or a plain link in the bar) was chosen; the menu closes after it. Call event.preventDefault() to stay on the page.
label
string
default "Main"
The navigation landmark's accessible name.
travel
number
default 16
How far the content slides in the direction of travel as it crossfades, in px. 0 is a plain crossfade.
bridge
"off" | "on" | "show"
default "on"
The safe triangle that keeps a menu open while the pointer crosses other triggers on its way to the panel; show draws it as a translucent wedge.
delay
number
default 120
How long the pointer rests on a trigger before a closed menu opens, and inside the bridge before it gives way, in ms.
closeDelay
number
default 260
How long a menu stays open after the pointer leaves the bar and the panel, in ms.
align
"center" | "start"
default "center"
The panel centred under its trigger, or starting at it; either way it is held inside the bar.
offset
number
default 6
The gap between the bar and the panel, in px.
notch
boolean
default true
Draw a notch on the panel's top edge pointing at the open trigger.
scrim
boolean
default true
Dim the page under the bar while a menu is open.
size
"sm" | "md" | "lg"
default "md"
Bar height 32, 40 or 48px, with trigger text to match.
accent
string
default "var(--accent-bright)"
Any CSS colour for the open trigger's rule, the bridge and link icons on hover.
start
React.ReactNode
default —
Content before the triggers, such as a brand mark.
end
React.ReactNode
default —
Content at the bar's end, such as sign-in actions.
children
React.ReactNode
default —
The page under the bar. With it, the panel floats over the page, its height is capped to the room there, and it never leaves the component's box.
sound
boolean
default false
A swish when a press or a key opens or closes a menu, and a tick when a key moves the panel between triggers or within it. Hover-driven changes are silent, so a pointer passing over the bar never starts audio.
disabled
boolean
default false
Shows the bar closed and ignores hovers, presses and keys.
className
string
default —
Classes for the root element.