Morphos
Layout

NavigationMenu

A site navigation bar with expandable submenus, sharing active-item state across a compound of parts.

Interactive example

Installation

npm install @morphos/layout
pnpm add @morphos/layout
yarn add @morphos/layout
bun add @morphos/layout

Import

import {
  NavigationMenu,
  NavigationMenuList,
  NavigationMenuItem,
  NavigationMenuTrigger,
  NavigationMenuContent,
  NavigationMenuLink,
} from '@morphos/layout'

Usage

@Component()
class MyComponent extends StatefulComponent {
  @State() nav = new NavigationMenu({ 'aria-label': 'Main navigation' })
  @State() productsItem = new NavigationMenuItem({ nav: this.nav, value: 'products' })

  render() {
    return (
      <NavigationMenu nav={this.nav}>
        <NavigationMenuList nav={this.nav}>
          <NavigationMenuItem nav={this.nav} value="products">
            <NavigationMenuTrigger item={this.productsItem}>Products</NavigationMenuTrigger>
            <NavigationMenuContent item={this.productsItem}>
              <NavigationMenuLink href="/analytics">Analytics</NavigationMenuLink>
              <NavigationMenuLink href="/automation">Automation</NavigationMenuLink>
            </NavigationMenuContent>
          </NavigationMenuItem>

          <li>
            <NavigationMenuLink href="/pricing">Pricing</NavigationMenuLink>
          </li>
        </NavigationMenuList>
      </NavigationMenu>
    )
  }
}

Plain links that don't need a submenu can skip NavigationMenuItem entirely and sit directly in an <li> inside NavigationMenuList, as shown with "Pricing" above.

Compound components

ComponentDescription
NavigationMenuRoot — renders <nav>, tracks which item's submenu is active
NavigationMenuListRenders <ul role="list">
NavigationMenuItemOne item in the list — bridges the root and its trigger/content
NavigationMenuTriggerButton that expands/collapses the item's submenu
NavigationMenuContentThe submenu panel
NavigationMenuLinkA plain navigation link (<a>)

Props — NavigationMenu

PropTypeDefaultDescription
orientation"horizontal" | "vertical""horizontal"Layout direction
aria-labelstringAccessible label for the <nav>
classstringCSS class
idstringHTML id

Methods — NavigationMenu

MethodDescription
open(item: string)Opens the submenu for the given item value, closing any other open one
close()Closes the currently open submenu
toggle(item: string)Opens the given item's submenu if closed, or closes it if it's the currently open one

Props — NavigationMenuList

PropTypeDefaultDescription
navNavigationMenuThe root NavigationMenu instance
childrenChildrenNavigationMenuItem and plain <li> elements
classstringCSS class
idstringHTML id

Props — NavigationMenuItem

PropTypeDefaultDescription
navNavigationMenuThe root NavigationMenu instance
valuestringUnique identifier for this item
childrenChildrenTypically a NavigationMenuTrigger + NavigationMenuContent pair
classstringCSS class
idstringHTML id

Props — NavigationMenuTrigger

PropTypeDefaultDescription
itemNavigationMenuItemThe parent NavigationMenuItem
childrenChildrenTrigger label
classstringCSS class
idstringHTML id (defaults to the item's generated trigger id)

Props — NavigationMenuContent

PropTypeDefaultDescription
itemNavigationMenuItemThe parent NavigationMenuItem
childrenChildrenSubmenu content
classstringCSS class
idstringHTML id (defaults to the item's generated content id)
PropTypeDefaultDescription
hrefstringLink destination
targetstringAnchor target attribute
relstringAnchor rel attribute
onClick(event: MouseEvent) => voidClick handler
childrenChildrenLink content
classstringCSS class
idstringHTML id

Keyboard and pointer interaction

InteractionAction
Click a triggerToggle its submenu open/closed; opening one closes any other open submenu
Click outside the trigger and contentClose the open submenu
EscapeClose the open submenu

Arrow-key navigation between triggers or between links inside a submenu is not implemented — NavigationMenuContent only listens for Escape and outside mousedown on document while its item's submenu is open.

data-* attributes

AttributeElementWhen present
data-orientationNavigationMenuAlways — reflects the orientation prop
data-activeNavigationMenuItemThe item's submenu is currently open

There is no data-open attribute on NavigationMenuTrigger or NavigationMenuContent — only NavigationMenuItem exposes state, via data-active. NavigationMenuContent uses the native hidden attribute to hide closed submenus.

Styling example

.morphos-navigation-menu[data-orientation="vertical"] .morphos-navigation-menu-list {
  flex-direction: column;
  align-items: stretch;
}

.morphos-navigation-menu-trigger:hover,
.morphos-navigation-menu-item[data-active] .morphos-navigation-menu-trigger {
  background: var(--morphos-color-bg-hover);
}

.morphos-navigation-menu-content[hidden] {
  display: none;
}

On this page