Navigation Menu
Combine native links and expandable navigation panels in one bar.
Usage
Product
Combine native product links with disclosure triggers in one navigation surface.
Combine native product links with disclosure triggers in one navigation surface.
<!-- Navigation Menu / Product -->
<script setup lang="ts">
import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuViewport, NavigationMenuLink } from '@sectile/vue/navigation-menu'
const items = [
{ id: 'products', parentID: null },
{ id: 'releases', parentID: 'products' },
{ id: 'open-source', parentID: 'products' },
{ id: 'docs', parentID: null },
]
</script>
<template>
<NavigationMenuRoot :items="items" label="Product navigation" v-slot="{ openPath }">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger value="products" as="button">Products</NavigationMenuTrigger>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink value="docs" as="a" href="/docs">Documentation</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
<NavigationMenuViewport v-show="openPath.includes('products')">
<NavigationMenuContent for="products">
<NavigationMenuLink value="releases" as="a" href="/releases">New releases</NavigationMenuLink>
<NavigationMenuLink value="open-source" as="a" href="/open-source">Open source</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuViewport>
</NavigationMenuRoot>
</template>Links
Preserve native link navigation alongside compound menu triggers.
Preserve native link navigation alongside compound menu triggers.
<!-- Navigation Menu / Links -->
<script setup lang="ts">
import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuTrigger, NavigationMenuContent, NavigationMenuViewport, NavigationMenuLink } from '@sectile/vue/navigation-menu'
const items = [
{ id: 'resources', parentID: null },
{ id: 'guides', parentID: 'resources' },
{ id: 'api', parentID: 'resources' },
{ id: 'github', parentID: null },
]
</script>
<template>
<NavigationMenuRoot :items="items" label="Developer resources" v-slot="{ openPath }">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuTrigger value="resources" as="button">Resources</NavigationMenuTrigger>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink value="github" as="a" href="https://github.com/sectile">GitHub</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
<NavigationMenuViewport v-show="openPath.includes('resources')">
<NavigationMenuContent for="resources">
<NavigationMenuLink value="guides" as="a" href="/guide">Guides</NavigationMenuLink>
<NavigationMenuLink value="api" as="a" href="/api">API reference</NavigationMenuLink>
</NavigationMenuContent>
</NavigationMenuViewport>
</NavigationMenuRoot>
</template>Disabled
Remove the control from keyboard and pointer interaction.
Remove the control from keyboard and pointer interaction.
<!-- Navigation Menu / Disabled -->
<script setup lang="ts">
import { NavigationMenuRoot, NavigationMenuList, NavigationMenuItem, NavigationMenuLink } from '@sectile/vue/navigation-menu'
const items = [
{ id: 'profile', parentID: null },
{ id: 'billing', parentID: null },
]
</script>
<template>
<NavigationMenuRoot :items="items" :disabled-items="['billing']" label="Account navigation">
<NavigationMenuList>
<NavigationMenuItem>
<NavigationMenuLink value="profile" as="a" href="/profile">Profile</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem>
<NavigationMenuLink value="billing" as="span">Billing unavailable</NavigationMenuLink>
</NavigationMenuItem>
</NavigationMenuList>
</NavigationMenuRoot>
</template>API
Vue package: @sectile/vue/navigation-menu
NavigationMenuRootNavigationMenuLinkNavigationMenuTriggerNavigationMenuContentNavigationMenuListNavigationMenuItemNavigationMenuViewportNavigationMenuIndicator
Props
NavigationMenuItemProps
as- Type
PrimitiveAsDefault'li'Element or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
disabled- Type
booleanDefaultundefinedWhether interaction is unavailable.
value- Type
stringDefaultRequiredCurrent value exposed by this contract.
NavigationMenuRootProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
defaultHighlightedValue- Type
string | nullDefaultundefinedInitially highlighted value for uncontrolled state.
disabled- Type
booleanDefaultundefinedWhether interaction is unavailable.
disabledItems- Type
readonly string[]DefaultundefinedItem values excluded from focus and selection.
items- Type
readonly MenuItemDefinition<string>[]DefaultRequiredOrdered item values managed by the component.
label- Type
stringDefaultundefinedAccessible name announced for the control.
policies- Type
MenuPolicies<string>DefaultundefinedBehavior policies that customize validation, movement, or selection.
textValue- Type
(id: string) => stringDefaultundefinedReturns searchable or presentational text for an item value.
NavigationMenuContentProps
as- Type
PrimitiveAsDefaultundefinedElement or component rendered for this part.
asChild- Type
booleanDefaultundefinedWhether to merge this part into its single child instead of rendering a wrapper.
for- Type
stringDefaultRequiredValue or ID of the related part targeted by this component.
Slots
NavigationMenuItemSlotProps
disabled- Type
booleanWhether interaction is unavailable.
highlighted- Type
booleanWhether this item is highlighted for interaction.
open- Type
booleanWhether the associated popup or disclosure is open.
value- Type
stringCurrent value exposed by this contract.
NavigationMenuRootSlotProps
disabled- Type
booleanWhether interaction is unavailable.
highlightedValue- Type
string | nullValue currently highlighted for interaction.
open- Type
booleanWhether the associated popup or disclosure is open.
openPath- Type
readonly string[]Ordered values in the open menu path.
Events
NavigationMenuRoot
invoke- Payload
stringEmitted when the current action is invoked.
update:open- Payload
booleanEmitted when the component requests a new open state.
Parts
Shared scope: [data-scope="navigation-menu"]. Combine it with a part selector to keep styles local to this component.
| Part | Selector | Role | Extra attributes |
|---|---|---|---|
root | [data-part="root"] | Defines the component boundary and owns its composed parts. | — |
list | [data-part="list"] | Groups the component items in navigation order. | — |
item-container | [data-part="item-container"] | Positions one top-level item and its nested content. | — |
item | [data-part="item"] | Menu item at any hierarchy depth; use data-level to distinguish top-level and nested items | data-level="<depth>" |
sub-content | [data-part="sub-content"] | Popup content owned by a parent menu item | data-level="<depth>" |
viewport | [data-part="viewport"] | Clips and positions the currently visible content. | — |
indicator | [data-part="indicator"] | Shows state or position without replacing the primary content. | — |
Keyboard interaction
| Key | Behavior |
|---|---|
| Arrow Left / Arrow Right | Move between root menu items. |
| Arrow Down / Arrow Up | Open a branch or move inside its vertical item list. |
| Home / End | Move to the first or last item at the current level. |
| Enter / Space | Open a branch or invoke the current item. |
| Escape | Close the branch and return to its owner. |
Accessibility
Native links keep link semantics while disclosure triggers expose expanded state for compound panels.
See the corresponding WAI-ARIA pattern for the host accessibility contract.
