NavigationMenu
A website-style multi-level navigation bar: top-level triggers open a unified viewport panel (mega-panel multi-column link cards) on hover/click, with delayed open/close, a controlled open value, and full keyboard navigation. Leaf items with href render as links.
Basic usage (mega panel)
Basic usage
Controlled open (value + oas-change)
Event semantics:
oas-changeis an open/close event — it fires when a group expands or collapses the panel (value= the open top-level item); leaf selection goes throughoas-select. When embedding the menu inside a host container (popover/drawer etc.), do NOT listen tooas-changeto "navigate and close the container" — that closes the container right as the panel expands. Listen tooas-selectfor close-on-navigate instead.
Controlled open
Delayed open/close
Delayed open/close
Vertical orientation
Vertical
Multi-column grid
Multi-column grid (columns=3)
Icon color (iconColor)
Panel link-card icons accept an iconColor field (fixes the icon color, overriding the selected/disabled default); it defaults to currentColor following the text color. The declarative child channel uses the icon-color attribute.
Icon color (iconColor)
Backdrop + keep-mounted + arrow
Backdrop + keep-mounted + arrow
backdrop shows an overlay when open; keep-mounted keeps the panel DOM after closing; arrow shows the pointer arrow.
Disabled items
Disabled items
Arrow follows the trigger
By default the popup arrow doesn't point at any trigger; once the panel opens, JS writes the arrow position from the current trigger's offset/width, and the arrow follows when you switch triggers.
Arrow follows the trigger
Hover/click "Products" then "Resources": the arrow follows the open trigger.
Collision flip (the boundary is the viewport)
By default the panel's writing-start edge follows the active trigger (left edge in LTR / right edge in RTL): neither the nav bar nor any outer container is a clipping boundary, so the panel may overflow both (a shrink-to-fit nav bar is always overflowed). The panel flips only when the followed panel would overflow the viewport's right edge — then its right edge aligns to the trigger's right edge and still stays inside the viewport; when the panel's bottom would overflow the viewport it flips up (flip-up); with enough room it keeps the normal start-edge-following position. Narrow the browser window until the panel no longer fits to see the flip.
A narrow container is not a clipping boundary (left edge follows the trigger)
The container is only 120px (narrower than the panel) and the nav bar itself is only slightly wider than its trigger, while the panel's width grows with its content (bottoming out at the content's min-content, not a fixed width): overflowing the container and the nav bar neither flips nor clips the panel (neither is a clipping boundary) — its left edge keeps following the trigger. The flip is viewport-driven only: narrow the browser window until the panel no longer fits and it right-aligns.
Sub second-level cascade
A panel item with a sub field (second-level nav data) renders a "sub trigger"; clicking opens an overlay second-level panel inside the panel (slide-in cascade animation): Esc / ← steps back to the main panel (focus returns to the trigger), another Esc closes the whole panel; ↓ moves between the second-level links (skipping disabled ones), Enter selects. Coexists with the inline section folding (sub takes precedence over children).
Sub second-level cascade
Marketing slot (panel-footer)
slot="panel-footer" renders a footer container at the bottom of the panel (CTA cards etc.) — only when it has content; it opens together with the panel, and the --vp-h height transition includes it.
panel-footer marketing slot
A marketing area appears at the bottom of the panel (only rendered when it has content).
Declarative child channel
Besides the items JSON, you can write items declaratively with <oas-navigation-menu-item> (the items attribute wins when explicitly set). The default slot text is the label; attributes map to the NavItem/MenuItem scalar fields (value/href/target/icon/description/active/disabled etc.). Direct child items recurse into children (inline second-level nav inside the panel); an item with the sub attribute parses its children into the overlay second-level nav; <oas-navigation-menu-group> is the group carrier (type: "group" semantics — its items are flattened into the grid). Child additions/removals, attribute and text changes re-render automatically.
Child channel basic
Second-level cascade (sub) and groups
With the `sub` attribute the children render as an overlay second-level nav inside the panel; group carrier items are flattened into the grid.
API
oas-navigation-menu
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
arrow | Pointer arrow on the popup, shown by default; arrow="false" hides it | string | true |
backdrop | Show an overlay when open (clicking the overlay closes) | boolean | — |
columns | Panel grid columns, default 2 (mega-panel multi-column link cards) | string | 2 |
delay-duration | Hover open/close delay in ms, default 200; clicks and keyboard are immediate | string | 200 |
items | Navigation items JSON (hierarchical; leaf items can carry description text and an icon to render mega-panel link cards) | string | [] |
keep-mounted | Keep the panel DOM mounted when closed (crawler/SEO indexing) | boolean | — |
loop | Top-level arrow-key wrap-around toggle, default true (loops at edges); explicit loop="false" stops at the edges (aligned with menubar) | string | — |
orientation | Layout direction: horizontal (default) / vertical (panel appears to the right of triggers) | string | horizontal |
skip-delay-duration | Skip-delay window in ms, default 300: hovering another trigger within this window after a close opens it immediately | string | 300 |
value | Controlled open item (top-level trigger value; empty string = closed; when present the open state follows the attribute and interactions only dispatch oas-change for the host to update) | string | — |
Events
| Event | Description |
|---|---|
oas-change | The open item changed (open/close semantics: dispatched when a group expands or collapses, NOT a leaf selection), detail: { value } (value is the open top-level item value; empty string = closed); listen to oas-select for leaf selection — do not use this event to navigate or close containers |
oas-select | An item was selected (top-level leaf link, panel link card or secondary sub-nav link), detail: { value } |
Slots
| Name | Description |
|---|---|
panel-footer | Marketing slot at the bottom of the panel: <div slot="panel-footer"> (CTA cards etc.) renders a footer container inside the panel when it has content |
CSS Variables
| CSS Variable | Default |
|---|---|
--oas-nav-panel-max-height | 60vh |
--oas-navigation-menu-arrow-height | 12px |
--oas-navigation-menu-arrow-radius | 0 |
--oas-navigation-menu-arrow-width | 12px |
oas-navigation-menu-item
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
active | Current-page marker: the link renders aria-current="page" (applies to top-level and panel links) | — | — |
danger | Destructive item (red semantics) | — | — |
description | Link-card description: rendered under the title in mega-panel mode | — | — |
disabled | Disabled: renders aria-disabled and blocks clicks/keyboard/hover | — | — |
href | Link URL: leaf items with href render as <a> (top-level and panel link cards) | — | — |
icon | Icon name (@oas-ui/icons registry icon name): panel link-card icon | — | — |
icon-color | Icon color: fixes the icon to this color (overrides the selected/disabled default); defaults to currentColor following the text color | — | — |
kind | Leaf item semantics: radio (default) / action / checkbox | — | — |
loading | Loading: blocks interaction until data-driven recovery | — | — |
rel | Link rel (custom, e.g. noopener) | — | — |
sub | Boolean: when present its direct child items parse into sub (overlay second-level nav inside the panel); otherwise they recurse into children (inline secondary sub-nav) | — | — |
target | Link open target (e.g. _blank) | — | — |
value | Selection value (required): top-level triggers and panel items use it for open/select/keyboard | — | — |
Slots
| Name | Description |
|---|---|
| default | Navigation item label content (default slot text; direct child items/group carriers are excluded) |
oas-navigation-menu-group
Attributes
| Attribute | Description | Type | Default |
|---|---|---|---|
label | Optional group title (not rendered by this component's panel — it only carries data, matching the type: "group" field of the JSON channel) | — | — |
Slots
| Name | Description |
|---|---|
| default | Grouped navigation items (oas-navigation-menu-item children, flattened into the grid when the panel renders) |
NavItem fields (inherits MenuItem):
| Field | Description | Type |
|---|---|---|
label | Navigation text | string |
value | Selection value | string |
href | Link URL (optional); leaf items with href render as <a> and are navigable | string |
target | Link open target (optional) | string |
icon | Icon name (optional); panel link-card icon | string |
iconColor | Icon color (optional): fixes the icon to this color, overriding the selected/disabled default; defaults to currentColor following the text color | string |
description | Link-card description (optional); rendered under the title in mega-panel mode | string |
active | Current-page marker (optional); renders aria-current="page" on the link | boolean |
disabled | Disabled | boolean |
children | Sub navigation items (optional); a top-level item with children opens the mega panel, and panel children with children render as an inline secondary sub-nav | NavItem[] |
Interaction: hover (after delay-duration) / click a top-level trigger to open the unified viewport panel; click a panel link card to select and fire oas-select; the open item change fires oas-change. Clicking outside closes; Esc closes the panel; ←/→ (vertical ↑/↓) switch top level, ↓ (vertical →) opens the panel and focuses the first item, ↓/↑ move within the panel, → expands an inline secondary sub-nav, Enter selects; while the panel is open Tab cycles among panel items (focus trap).