Skip to main content

Navigation Menu

Overview

Use the Navigation Menu family when you need authored navigation items with optional dropdown panels, keyboard navigation, animated viewport transitions, and a mobile drawer helper that automatically derives its structure from the desktop menu. The desktop family is composed of six components that nest together, plus a separate mobile helper and an explicit mobile-only node for complex mega-menu content.

The root component manages open state, keyboard navigation, and optional animated viewport behavior. Navigation Menu Mobile is a separate component placed elsewhere on the page — it connects to the desktop menu by a shared menuId and builds a drawer-based mobile experience at runtime.

Authoring Structure

The desktop menu follows a strict nesting hierarchy:

Navigation Menu (desktop root)
└── Navigation Menu List
├── Navigation Menu Item
│ ├── plain link
│ ├── OR Navigation Menu Trigger + Navigation Menu Content
│ │ └── optional Navigation Menu Mobile Item subtree inside content
│ └── OR link + Navigation Menu Trigger + Navigation Menu Content
└── Navigation Menu Item ...

Navigation Menu Mobile (separate — anywhere on the page)

Desktop and Mobile Are Separate

Navigation Menu Mobile is not nested inside Navigation Menu. It is placed as a sibling element elsewhere on the page (typically inside the header shell alongside the desktop navigation). Both components share the same menuId value so the mobile helper can find and mirror the desktop structure at runtime.

In header patterns, the typical structure is:

Header Shell
├── Brand
├── Navigation Menu (desktop, menuId="primary-nav")
│ └── Navigation Menu List ...
├── Actions
└── Navigation Menu Mobile (separate, menuId="primary-nav")

Placement Rules

ComponentPlacementRole
Navigation MenuTop-level wrapper for the desktop navigation.Owns orientation, open-state coordination, viewport behavior, and the menu identity.
Navigation Menu ListDirect child of Navigation Menu.Groups authored top-level menu items. The runtime scans for this list when initializing.
Navigation Menu ItemDirect child of Navigation Menu List.One navigation entry — a plain link, a dropdown parent, or both.
Navigation Menu TriggerInside Navigation Menu Item.Interactive button that opens a dropdown panel.
Navigation Menu ContentInside Navigation Menu Item, alongside a trigger.Dropdown or mega-menu panel content.
Navigation Menu Mobile ItemInside Navigation Menu Content.Declares an explicit mobile tree for complex mega-menu content.
Navigation Menu MobileSeparate from the desktop menu — anywhere on the page, connected by menuId.Mirrors the desktop menu into a drawer-based mobile experience at runtime.

Quick Start

Basic dropdown menu
<OmeNavigationMenu identity='{{"menuId":"primary-nav"}}'>
{#slot default}
<OmeNavigationMenuList>
{#slot default}
<OmeNavigationMenuItem>
{#slot default}
<OmeNavigationMenuTrigger settings='{{"showArrow":true,"triggerAction":"click"}}'>
{#slot default}Products{/slot}
</OmeNavigationMenuTrigger>
<OmeNavigationMenuContent>
{#slot default}
<a href="/shop">Shop all products</a>
{/slot}
</OmeNavigationMenuContent>
{/slot}
</OmeNavigationMenuItem>

<OmeNavigationMenuItem>
{#slot default}
<a href="/about">About</a>
{/slot}
</OmeNavigationMenuItem>
{/slot}
</OmeNavigationMenuList>
{/slot}
</OmeNavigationMenu>
Adding the mobile drawer helper
<!-- Desktop menu -->
<OmeNavigationMenu
identity='{{"menuId":"primary-nav"}}'
settings='{{"useAnimatedMenu":true,"useFullWidth":true,"fullWidthTargetSelector":".site-shell"}}'
>
{#slot default}
<OmeNavigationMenuList>
{#slot default}
<OmeNavigationMenuItem>
{#slot default}
<OmeNavigationMenuTrigger settings='{{"showArrow":true,"triggerAction":"click"}}'>
{#slot default}Services{/slot}
</OmeNavigationMenuTrigger>
<OmeNavigationMenuContent>
{#slot default}
<a href="/services/design">Design</a>
<a href="/services/dev">Development</a>
{/slot}
</OmeNavigationMenuContent>
{/slot}
</OmeNavigationMenuItem>
{/slot}
</OmeNavigationMenuList>
{/slot}
</OmeNavigationMenu>

<!-- Mobile helper (separate, linked by menuId) -->
<OmeNavigationMenuMobile
identity='{{"menuId":"primary-nav"}}'
content='{{"triggerLabel":"Open menu"}}'
/>

The mobile helper reads the desktop menu structure at runtime and generates a drawer-based mobile navigation. No duplicate authoring is needed.


Family Components

The root component wraps all desktop navigation items and manages shared behavior: orientation, keyboard navigation, animated viewport mode, and the menu identity used by the mobile helper. It does not render significant visible UI itself — only a container element and an optional viewport.

Structure Props

PropTypeDefaultDescription
tagstringnav

HTML tag for the root element. Defaults to nav for proper landmark semantics.

Identity Props

PropTypeDefaultDescription
menuIdstring""

Shared menu ID that Navigation Menu Mobile uses to find and connect to this desktop menu. Set this to the same value on both components to enable mobile mirroring.

Settings Props

PropTypeDefaultDescription
orientation"horizontal" | "vertical"horizontal

Root orientation. Affects which arrow keys navigate between triggers and the layout direction. Use vertical for stacked or sidebar menu structures.

useAnimatedMenubooleanfalse

Enables the generated viewport that animates dropdown panel changes. When enabled, content panels are portaled into a viewport container with smooth height transitions and directional motion.

useFullWidthbooleanfalse

Makes the animated viewport align to a wider container instead of the trigger width. Requires useAnimatedMenu to be enabled and a fullWidthTargetSelector to be set.

fullWidthTargetSelectorstring""

CSS selector used to find the container element whose width the viewport should match. Only visible when useFullWidth is enabled. Can be a class selector like .site-shell.

Styling Props

PropTypeDefaultDescription
classclassome-nav-menu-default

CSS class applied to the root element.

viewportClassclassome-nav-menu-default__viewport

CSS class applied to the generated animated viewport container. Only visible when useAnimatedMenu is enabled.

Animated Viewport Mode

When useAnimatedMenu is true, the root component generates a viewport container that houses all dropdown panels. This enables:

  • Smooth height transitions as panels open and close.
  • Directional motion animations when switching between panels (content slides in from the direction of the newly focused trigger).
  • Full-width mode that aligns the viewport to a wider parent container for mega-menu layouts.

Animated mode only activates for horizontal orientation and is automatically disabled inside the Etch builder (where it falls back to a non-animated preview).

Keyboard Behavior

When a trigger has focus in a horizontal menu:

KeyAction
Enter / SpaceToggle the associated panel.
ArrowRightMove focus to the next trigger.
ArrowLeftMove focus to the previous trigger.
ArrowDownOpen the dropdown panel.
HomeMove focus to the first trigger.
EndMove focus to the last trigger.
EscapeClose the open panel and return focus to its trigger.

In a vertical menu, ArrowDown / ArrowUp navigate between triggers and ArrowRight opens the panel.

Navigation wraps by default — pressing ArrowRight on the last trigger focuses the first, and vice versa.

Accessibility

The runtime wires up ARIA attributes automatically:

  • Each trigger has aria-expanded and aria-haspopup="menu" that update as panels open and close.
  • Each content panel has role="menu" and syncs aria-hidden with its open state.
  • data-ome-state attributes (open / closed) are set on items, triggers, and content for CSS targeting.

The list container groups top-level menu items. The runtime scans for the direct Navigation Menu List child when initializing the root component.

Styling Props

PropTypeDefaultDescription
classclassome-nav-menu-default__list

CSS class applied to the list element.

The list always renders as a <ul> element with display: flex and reset list styles. In horizontal mode the flex direction is row; in vertical mode it becomes column.


Each NavigationMenuItem represents one navigation entry. It can contain a plain link, a trigger-plus-content dropdown pair, or a combination of both (a link that also opens a dropdown).

Settings Props

PropTypeDefaultDescription
disabledbooleanfalse

Disables this item and any trigger it contains. Disabled items cannot be opened or focused for activation.

Styling Props

PropTypeDefaultDescription
classclassome-nav-menu-default__item

CSS class applied to the item element.

The item always renders as an <li> element. The runtime tracks open/closed state via data-ome-state on the item.


The interactive button users click or hover to open a dropdown panel. The trigger always renders as a <button> element and can optionally display a built-in chevron icon.

Settings Props

PropTypeDefaultDescription
disabledbooleanfalse

Prevents this trigger from opening its content panel. Overrides the item-level disabled prop.

showArrowbooleanfalse

Shows a built-in chevron icon inside the trigger button. The chevron rotates 180 degrees when the panel is open.

triggerAction"hover" | "click"hover

Preferred interaction mode. hover opens the panel on mouse enter with a small delay; click requires an explicit click. Inside the Etch builder, all triggers behave as click for reliable editing.

Styling Props

PropTypeDefaultDescription
classclassome-nav-menu-default__trigger

CSS class applied to the trigger button.

Trigger Interaction Modes

  • hover — The panel opens when the cursor enters the trigger area (with a 50ms delay) and closes when the cursor leaves the entire navigation boundary (trigger + content + viewport). This is the default and provides the smoothest desktop experience.
  • click — The panel only opens on explicit click. A document-level click listener closes the panel when clicking outside the navigation root.

Both modes support keyboard activation via Enter / Space.


The dropdown or mega-menu panel paired with a trigger. Content panels are hidden by default and become visible when their sibling trigger opens them.

Styling Props

PropTypeDefaultDescription
classclassome-nav-menu-default__content

CSS class applied to the content panel.

Runtime Behavior

  • In non-animated mode, content is positioned absolutely below its trigger item (or to the right in vertical orientation).
  • In animated mode, content is portaled into the shared viewport container and animated with presence state transitions.
  • Content panels use role="menu", aria-hidden, and data-ome-state that sync between open and closed.
  • The hidden attribute is toggled to control visibility.

A separate component that mirrors the desktop navigation into a drawer-based mobile experience. It is not nested inside Navigation Menu — it is placed elsewhere on the page and connects to the desktop menu via a shared menuId.

At runtime, the mobile helper:

  1. Finds the desktop Navigation Menu root by matching menuId.
  2. Extracts the menu structure recursively (or reads explicit Navigation Menu Mobile Item nodes if present).
  3. Generates a panel-based mobile drawer with sliding navigation and a back button.

In the Etch builder, the helper shows a static preview instead of live-extracted mobile navigation.

Identity Props

PropTypeDefaultDescription
menuIdstringome-mobile-nav

Must match Navigation Menu.identity.menuId. The mobile helper uses this value to find the desktop menu and wire its internal drawer.

Settings Props

PropTypeDefaultDescription
drawerDirection"left" | "right" | "top" | "bottom"left

Direction the mobile drawer slides from.

dismissiblebooleantrue

Allows overlay click and Escape to close the mobile drawer.

Content Props

PropTypeDefaultDescription
showTriggerLabelbooleantrue

When enabled, the trigger displays visible label text. When disabled, only a hamburger icon is shown with a separate triggerAriaLabel for screen readers.

triggerLabelstringMenu

Visible label text and accessible name for the drawer trigger. Only shown when showTriggerLabel is true.

triggerAriaLabelstringMenu

Screen-reader-only label for the trigger button when showTriggerLabel is false.

backButtonLabelstringBack

Fallback label used by the back button when the backButton slot is empty.

Root Styling Props

PropTypeDefaultDescription
classclassome-mobile-nav-default

CSS class applied to the mobile helper wrapper.

Control Styling Props

PropTypeDefaultDescription
triggerClassclassome-mobile-nav-default__trigger

CSS class applied to the drawer trigger button.

backButtonClassclassome-mobile-nav-default__back

CSS class applied to the back button.

closeButtonClassclassome-mobile-nav-default__close

CSS class applied to the icon-only close button.

Drawer Styling Props

PropTypeDefaultDescription
drawerClassclassome-mobile-nav-default__drawer

CSS class applied to the internal drawer root.

headerClassclassome-mobile-nav-default__header

CSS class applied to the drawer header row.

contentClassclassome-mobile-nav-default__content

CSS class applied to the drawer content wrapper.

Menu Styling Props

PropTypeDefaultDescription
listClassclassome-mobile-nav-default__list

CSS class applied to generated root and child lists.

itemClassclassome-mobile-nav-default__item

CSS class applied to generated list items.

linkClassclassome-mobile-nav-default__link

CSS class applied to generated links.

submenuTriggerClassclassome-mobile-nav-default__submenu-trigger

CSS class applied to generated submenu trigger buttons.

nextIconClassclassome-mobile-nav-default__next-icon

CSS class applied to the chevron icon shown on generated submenu triggers.

Slot Styling Props

PropTypeDefaultDescription
beforeClassclassome-mobile-nav-default__before

CSS class applied to the wrapper around the before slot.

afterClassclassome-mobile-nav-default__after

CSS class applied to the wrapper around the after slot.

Slots

SlotDescription
beforeRenders before generated items in the root panel only.
afterRenders after generated items in the root panel only.
backButtonReplaces the default back button content. If omitted, the button falls back to a back icon plus backButtonLabel.

Mobile Keyboard Behavior

Inside the mobile drawer, when a menu item has focus:

KeyAction
ArrowDownMove focus to the next menu item.
ArrowUpMove focus to the previous menu item.
HomeMove focus to the first menu item.
EndMove focus to the last menu item.
Enter / SpaceActivate the focused item (follow link or open submenu).
ArrowRightOpen a submenu (when focused on a submenu trigger).
Escape / ArrowLeftGo back to the previous panel.

How Content Extraction Works

The mobile helper extracts the navigation tree from the desktop menu in one of two ways:

  1. Explicit mobile items — If a Navigation Menu Content subtree contains at least one Navigation Menu Mobile Item, the helper uses only those explicit nodes for that panel and ignores regular auto-generated links.
  2. Automatic extraction — If no explicit mobile items exist, the helper recursively extracts the authored structure: links become mobile links, items with triggers become submenu branches, and nested navigation roots are traversed.

An explicit mobile-only node authored inside Navigation Menu Content when complex mega-menu content needs a custom mobile tree that differs from the auto-extracted structure. If a content panel contains at least one Navigation Menu Mobile Item, the mobile helper uses only those explicit nodes.

Structure Props

PropTypeDefaultDescription
tagstringdiv

HTML tag for the authored wrapper element. Common values are div, ul, li, or a depending on the structural role.

Settings Props

PropTypeDefaultDescription
useAs"trigger" | "link"trigger

Mobile node mode. trigger creates a submenu branch that navigates to a child panel. link creates a direct navigation link.

Content Props

PropTypeDefaultDescription
labelstring""

Label shown in the generated mobile drawer UI for this node.

Link Props

PropTypeDefaultDescription
hrefstring""

Destination URL. Required when useAs is link. Ignored for trigger nodes.

Styling Props

PropTypeDefaultDescription
classclass[]

Optional CSS class list for the authored wrapper element.

When to Use Mobile Items

Use Navigation Menu Mobile Item when your desktop mega-menu has complex content (cards, images, multi-column layouts) that should not be naively extracted into the mobile drawer. By wrapping mobile-relevant content in explicit mobile items, you control exactly what appears in the mobile navigation while keeping the desktop layout free to include richer visual content.


Common Mistakes

Placing items directly inside Navigation Menu

Do not place Navigation Menu Item blocks directly inside Navigation Menu. The runtime scans for a direct Navigation Menu List child at initialization. Always nest items inside a list.

Nesting Navigation Menu Mobile inside Navigation Menu

Navigation Menu Mobile is a separate component. It must not be placed inside the desktop Navigation Menu. Place it elsewhere on the page and connect it via menuId.

Missing trigger for dropdown content

If an item has Navigation Menu Content, it must also have a sibling Navigation Menu Trigger. Content without a trigger will not be openable.

Mismatched menuId values

The menuId on Navigation Menu Mobile.identity.menuId must exactly match Navigation Menu.identity.menuId. If the IDs do not match, the mobile helper will not find the desktop menu and the drawer will be empty.

Duplicating mobile content manually

Do not author a separate second menu tree for mobile. Navigation Menu Mobile derives its structure from the desktop menu automatically. Only use Navigation Menu Mobile Item when you need to customize the mobile tree for complex content.


FAQs

Can I use Navigation Menu without the mobile helper?

Yes. Navigation Menu Mobile is entirely optional. The desktop navigation family works standalone. Only add the mobile helper when you need a drawer-based mobile experience that mirrors the desktop menu.

How does the animated viewport work?

When useAnimatedMenu is enabled on the root component, dropdown content panels are portaled into a shared viewport container. The viewport smoothly transitions its height when panels open and close, and content panels animate with directional motion (slide in from the direction of the newly focused trigger). For full-width mega-menus, enable useFullWidth and set fullWidthTargetSelector to the container the viewport should align to.

What happens when both a link and a trigger are in the same item?

The item renders as a "link-branch" — the link is clickable for navigation and the trigger opens a dropdown. In the mobile drawer, this becomes a row with both a tappable link and a submenu chevron button.

Can I nest navigation menus?

Yes. You can place a Navigation Menu inside a Navigation Menu Content panel for multi-level navigation. Nested menus manage their own state independently. The animated viewport is automatically disabled for nested menus to avoid conflicts.

How do I customize the mobile drawer trigger?

Use showTriggerLabel to toggle between a labeled trigger and an icon-only trigger. When showTriggerLabel is false, set triggerAriaLabel for screen reader accessibility. Style the trigger using controlStyling.triggerClass. For the hamburger icon itself, the component renders a built-in SVG.

When should I use Navigation Menu Mobile Item?

Use it when your desktop mega-menu has complex visual content (cards, multi-column layouts, featured sections) that should not be auto-extracted into the mobile drawer. By wrapping mobile-relevant content in explicit Navigation Menu Mobile Item nodes, you control exactly what appears in the mobile navigation. Simple dropdown menus do not need explicit mobile items — the auto-extraction handles them well.