导航菜单

一个可以水平或垂直显示的链接列表。

用法

使用 items 属性,其值应为一个对象数组,对象包含以下属性:

  • label?: string
  • icon?: string
  • avatar?: AvatarProps
  • badge?: string | number | BadgeProps
  • trailingIcon?: string
  • type?: 'label' | 'link'
  • value?: string
  • disabled?: boolean
  • class?: any
  • slot?: string
  • onSelect?(e: Event): void
  • children?: NavigationMenuChildItem[]

你可以传递 Link 组件的任意属性,例如 totarget 等。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[]>([
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    to: '/getting-started',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        icon: 'i-lucide-swatch-book',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        icon: 'i-lucide-cog',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    to: '/composables',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.',
        to: '/composables/define-shortcuts'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.',
        to: '/composables/use-overlay'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.',
        to: '/composables/use-toast'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/components',
    active: true,
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.',
        to: '/components/link'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/components/modal'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.',
        to: '/components/navigation-menu'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.',
        to: '/components/pagination'
      },
      {
        label: 'Popover',
        icon: 'i-lucide-file-text',
        description: 'Display a non-modal dialog that floats around a trigger element.',
        to: '/components/popover'
      },
      {
        label: 'Progress',
        icon: 'i-lucide-file-text',
        description: 'Show a horizontal bar to indicate task progression.',
        to: '/components/progress'
      }
    ]
  },
  {
    label: 'GitHub',
    icon: 'i-simple-icons-github',
    badge: '3.8k',
    to: 'https://github.com/nuxt/ui',
    target: '_blank'
  },
  {
    label: 'Help',
    icon: 'i-lucide-circle-help',
    disabled: true
  }
])
</script>

<template>
  <UNavigationMenu :items="items" class="w-full justify-center" />
</template>
你也可以将一个二维数组传递给 items 属性来显示项目组。
每个项目都可以包含一个 children 对象数组,该数组包含以下属性以创建子菜单:
  • label: string
  • description?: string
  • icon?: string
  • class?: any
  • onSelect?(e: Event): void

方向

使用 orientation 属性来改变 NavigationMenu 的方向。

当方向为 vertical 时,使用 Collapsible 组件来显示子项。你可以使用 opendefaultOpen 属性来控制每个项目的展开状态。
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[][]>([
  [
    {
      label: 'Links',
      type: 'label'
    },
    {
      label: 'Guide',
      icon: 'i-lucide-book-open',
      children: [
        {
          label: 'Introduction',
          description: 'Fully styled and customizable components for Nuxt.',
          icon: 'i-lucide-house'
        },
        {
          label: 'Installation',
          description: 'Learn how to install and configure Nuxt UI in your application.',
          icon: 'i-lucide-cloud-download'
        },
        {
          label: 'Icons',
          icon: 'i-lucide-smile',
          description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
        },
        {
          label: 'Colors',
          icon: 'i-lucide-swatch-book',
          description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
        },
        {
          label: 'Theme',
          icon: 'i-lucide-cog',
          description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
        }
      ]
    },
    {
      label: 'Composables',
      icon: 'i-lucide-database',
      children: [
        {
          label: 'defineShortcuts',
          icon: 'i-lucide-file-text',
          description: 'Define shortcuts for your application.',
          to: '/composables/define-shortcuts'
        },
        {
          label: 'useOverlay',
          icon: 'i-lucide-file-text',
          description: 'Display a modal/slideover within your application.',
          to: '/composables/use-overlay'
        },
        {
          label: 'useToast',
          icon: 'i-lucide-file-text',
          description: 'Display a toast within your application.',
          to: '/composables/use-toast'
        }
      ]
    },
    {
      label: 'Components',
      icon: 'i-lucide-box',
      to: '/components',
      active: true,
      defaultOpen: true,
      children: [
        {
          label: 'Link',
          icon: 'i-lucide-file-text',
          description: 'Use NuxtLink with superpowers.',
          to: '/components/link'
        },
        {
          label: 'Modal',
          icon: 'i-lucide-file-text',
          description: 'Display a modal within your application.',
          to: '/components/modal'
        },
        {
          label: 'NavigationMenu',
          icon: 'i-lucide-file-text',
          description: 'Display a list of links.',
          to: '/components/navigation-menu'
        },
        {
          label: 'Pagination',
          icon: 'i-lucide-file-text',
          description: 'Display a list of pages.',
          to: '/components/pagination'
        },
        {
          label: 'Popover',
          icon: 'i-lucide-file-text',
          description: 'Display a non-modal dialog that floats around a trigger element.',
          to: '/components/popover'
        },
        {
          label: 'Progress',
          icon: 'i-lucide-file-text',
          description: 'Show a horizontal bar to indicate task progression.',
          to: '/components/progress'
        }
      ]
    }
  ],
  [
    {
      label: 'GitHub',
      icon: 'i-simple-icons-github',
      badge: '3.8k',
      to: 'https://github.com/nuxt/ui',
      target: '_blank'
    },
    {
      label: 'Help',
      icon: 'i-lucide-circle-help',
      disabled: true
    }
  ]
])
</script>

<template>
  <UNavigationMenu orientation="vertical" :items="items" class="data-[orientation=vertical]:w-48" />
</template>
当方向为 horizontal 时,组之间会有间距;当方向为 vertical 时,组之间会用分隔符分开。

高亮

使用 highlight 属性来为活动项目显示高亮边框。

使用 highlight-color 属性来改变边框的颜色。它默认使用 color 属性的值。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[][]>([
  [
    {
      label: 'Guide',
      icon: 'i-lucide-book-open',
      children: [
        {
          label: 'Introduction',
          description: 'Fully styled and customizable components for Nuxt.',
          icon: 'i-lucide-house'
        },
        {
          label: 'Installation',
          description: 'Learn how to install and configure Nuxt UI in your application.',
          icon: 'i-lucide-cloud-download'
        },
        {
          label: 'Icons',
          icon: 'i-lucide-smile',
          description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
        },
        {
          label: 'Colors',
          icon: 'i-lucide-swatch-book',
          description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
        },
        {
          label: 'Theme',
          icon: 'i-lucide-cog',
          description:
            'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
        }
      ]
    },
    {
      label: 'Composables',
      icon: 'i-lucide-database',
      children: [
        {
          label: 'defineShortcuts',
          icon: 'i-lucide-file-text',
          description: 'Define shortcuts for your application.',
          to: '/composables/define-shortcuts'
        },
        {
          label: 'useOverlay',
          icon: 'i-lucide-file-text',
          description: 'Display a modal/slideover within your application.',
          to: '/composables/use-overlay'
        },
        {
          label: 'useToast',
          icon: 'i-lucide-file-text',
          description: 'Display a toast within your application.',
          to: '/composables/use-toast'
        }
      ]
    },
    {
      label: 'Components',
      icon: 'i-lucide-box',
      to: '/components',
      active: true,
      defaultOpen: true,
      children: [
        {
          label: 'Link',
          icon: 'i-lucide-file-text',
          description: 'Use NuxtLink with superpowers.',
          to: '/components/link'
        },
        {
          label: 'Modal',
          icon: 'i-lucide-file-text',
          description: 'Display a modal within your application.',
          to: '/components/modal'
        },
        {
          label: 'NavigationMenu',
          icon: 'i-lucide-file-text',
          description: 'Display a list of links.',
          to: '/components/navigation-menu'
        },
        {
          label: 'Pagination',
          icon: 'i-lucide-file-text',
          description: 'Display a list of pages.',
          to: '/components/pagination'
        },
        {
          label: 'Popover',
          icon: 'i-lucide-file-text',
          description: 'Display a non-modal dialog that floats around a trigger element.',
          to: '/components/popover'
        },
        {
          label: 'Progress',
          icon: 'i-lucide-file-text',
          description: 'Show a horizontal bar to indicate task progression.',
          to: '/components/progress'
        }
      ]
    }
  ],
  [
    {
      label: 'GitHub',
      icon: 'i-simple-icons-github',
      badge: '3.8k',
      to: 'https://github.com/nuxt/ui',
      target: '_blank'
    },
    {
      label: 'Help',
      icon: 'i-lucide-circle-help',
      disabled: true
    }
  ]
])
</script>

<template>
  <UNavigationMenu
    highlight
    highlight-color="primary"
    orientation="horizontal"
    :items="items"
    class="data-[orientation=horizontal]:border-b border-default data-[orientation=horizontal]:w-full data-[orientation=vertical]:w-48"
  />
</template>
在此示例中,为 horizontal 方向应用了 border-b 类以显示边框,这不是默认行为,以便你有一个干净的基础进行开发。
vertical 方向中,highlight 属性只高亮活动子项的边框。

颜色

使用 color 属性来改变 NavigationMenu 的颜色。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[][]>([
  [
    {
      label: 'Guide',
      icon: 'i-lucide-book-open',
      to: '/getting-started'
    },
    {
      label: 'Composables',
      icon: 'i-lucide-database',
      to: '/composables'
    },
    {
      label: 'Components',
      icon: 'i-lucide-box',
      to: '/components',
      active: true
    }
  ],
  [
    {
      label: 'GitHub',
      icon: 'i-simple-icons-github',
      badge: '3.8k',
      to: 'https://github.com/nuxt/ui',
      target: '_blank'
    }
  ]
])
</script>

<template>
  <UNavigationMenu color="neutral" :items="items" class="w-full" />
</template>

变体

使用 variant 属性来改变 NavigationMenu 的变体/风格。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[][]>([
  [
    {
      label: 'Guide',
      icon: 'i-lucide-book-open',
      to: '/getting-started'
    },
    {
      label: 'Composables',
      icon: 'i-lucide-database',
      to: '/composables'
    },
    {
      label: 'Components',
      icon: 'i-lucide-box',
      to: '/components',
      active: true
    }
  ],
  [
    {
      label: 'GitHub',
      icon: 'i-simple-icons-github',
      badge: '3.8k',
      to: 'https://github.com/nuxt/ui',
      target: '_blank'
    }
  ]
])
</script>

<template>
  <UNavigationMenu color="neutral" variant="link" :items="items" class="w-full" />
</template>
highlight 属性改变 pill 变体下活动项目的样式。试一下看看区别。

尾随图标

使用 trailing-icon 属性来自定义每个项目的尾随 图标。默认为 i-lucide-chevron-down。此图标仅在项目有子项时显示。

你也可以通过在项目对象中使用 trailingIcon 属性来为特定项目设置图标。
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[]>([
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    to: '/getting-started',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        icon: 'i-lucide-swatch-book',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        icon: 'i-lucide-cog',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    to: '/composables',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.',
        to: '/composables/define-shortcuts'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.',
        to: '/composables/use-overlay'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.',
        to: '/composables/use-toast'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/components',
    active: true,
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.',
        to: '/components/link'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/components/modal'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.',
        to: '/components/navigation-menu'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.',
        to: '/components/pagination'
      },
      {
        label: 'Popover',
        icon: 'i-lucide-file-text',
        description: 'Display a non-modal dialog that floats around a trigger element.',
        to: '/components/popover'
      },
      {
        label: 'Progress',
        icon: 'i-lucide-file-text',
        description: 'Show a horizontal bar to indicate task progression.',
        to: '/components/progress'
      }
    ]
  }
])
</script>

<template>
  <UNavigationMenu trailing-icon="i-lucide-arrow-down" :items="items" class="w-full justify-center" />
</template>
你可以在全局配置 app.config.ts 中通过 ui.icons.chevronDown 键来自定义此图标。
你可以在全局配置 vite.config.ts 中通过 ui.icons.chevronDown 键来自定义此图标。

箭头

使用 arrow 属性在项目有子项时,为 NavigationMenu 内容显示箭头。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[]>([
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    to: '/getting-started',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        icon: 'i-lucide-swatch-book',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        icon: 'i-lucide-cog',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    to: '/composables',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.',
        to: '/composables/define-shortcuts'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.',
        to: '/composables/use-overlay'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.',
        to: '/composables/use-toast'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/components',
    active: true,
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.',
        to: '/components/link'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/components/modal'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.',
        to: '/components/navigation-menu'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.',
        to: '/components/pagination'
      },
      {
        label: 'Popover',
        icon: 'i-lucide-file-text',
        description: 'Display a non-modal dialog that floats around a trigger element.',
        to: '/components/popover'
      },
      {
        label: 'Progress',
        icon: 'i-lucide-file-text',
        description: 'Show a horizontal bar to indicate task progression.',
        to: '/components/progress'
      }
    ]
  }
])
</script>

<template>
  <UNavigationMenu arrow :items="items" class="w-full justify-center" />
</template>
箭头会动画跟随活动项目。

内容方向

使用 content-orientation 属性来改变内容的方向。

此属性仅在 orientationhorizontal 时有效。
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[]>([
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    to: '/getting-started',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    to: '/composables',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.',
        to: '/composables/define-shortcuts'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.',
        to: '/composables/use-overlay'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.',
        to: '/composables/use-toast'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/components',
    active: true,
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.',
        to: '/components/link'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/components/modal'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.',
        to: '/components/navigation-menu'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.',
        to: '/components/pagination'
      }
    ]
  }
])
</script>

<template>
  <UNavigationMenu arrow content-orientation="vertical" :items="items" class="w-full justify-center" />
</template>

卸载

使用 unmount-on-hide 属性来控制内容卸载行为。默认为 true

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = ref<NavigationMenuItem[]>([
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    to: '/getting-started',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        icon: 'i-lucide-swatch-book',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        icon: 'i-lucide-cog',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    to: '/composables',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.',
        to: '/composables/define-shortcuts'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.',
        to: '/composables/use-overlay'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.',
        to: '/composables/use-toast'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    to: '/components',
    active: true,
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.',
        to: '/components/link'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/components/modal'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.',
        to: '/components/navigation-menu'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.',
        to: '/components/pagination'
      },
      {
        label: 'Popover',
        icon: 'i-lucide-file-text',
        description: 'Display a non-modal dialog that floats around a trigger element.',
        to: '/components/popover'
      },
      {
        label: 'Progress',
        icon: 'i-lucide-file-text',
        description: 'Show a horizontal bar to indicate task progression.',
        to: '/components/progress'
      }
    ]
  }
])
</script>

<template>
  <UNavigationMenu :unmount-on-hide="false" :items="items" class="w-full justify-center" />
</template>
你可以检查 DOM 来查看每个项目的内容是否被渲染。

示例

控制活动项目

你可以使用 default-value 属性或使用 v-model 指令配合项目的索引来控制活动项目。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items: NavigationMenuItem[] = [
  {
    label: 'Guide',
    icon: 'i-lucide-book-open',
    children: [
      {
        label: 'Introduction',
        description: 'Fully styled and customizable components for Nuxt.',
        icon: 'i-lucide-house'
      },
      {
        label: 'Installation',
        description: 'Learn how to install and configure Nuxt UI in your application.',
        icon: 'i-lucide-cloud-download'
      },
      {
        label: 'Icons',
        icon: 'i-lucide-smile',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        icon: 'i-lucide-swatch-book',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        icon: 'i-lucide-cog',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database',
    children: [
      {
        label: 'defineShortcuts',
        icon: 'i-lucide-file-text',
        description: 'Define shortcuts for your application.'
      },
      {
        label: 'useOverlay',
        icon: 'i-lucide-file-text',
        description: 'Display a modal/slideover within your application.'
      },
      {
        label: 'useToast',
        icon: 'i-lucide-file-text',
        description: 'Display a toast within your application.'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    children: [
      {
        label: 'Link',
        icon: 'i-lucide-file-text',
        description: 'Use NuxtLink with superpowers.'
      },
      {
        label: 'Modal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.'
      },
      {
        label: 'NavigationMenu',
        icon: 'i-lucide-file-text',
        description: 'Display a list of links.'
      },
      {
        label: 'Pagination',
        icon: 'i-lucide-file-text',
        description: 'Display a list of pages.'
      },
      {
        label: 'Popover',
        icon: 'i-lucide-file-text',
        description: 'Display a non-modal dialog that floats around a trigger element.'
      },
      {
        label: 'Progress',
        icon: 'i-lucide-file-text',
        description: 'Show a horizontal bar to indicate task progression.'
      }
    ]
  }
]

const active = ref()

defineShortcuts({
  1: () => {
    active.value = '0'
  },
  2: () => {
    active.value = '1'
  },
  3: () => {
    active.value = '2'
  }
})
</script>

<template>
  <UNavigationMenu v-model="active" :items="items" class="w-full justify-center" />
</template>
在此示例中,利用 defineShortcuts,你可以通过按下 123 来切换活动项目。
如果提供了 value,你也可以传递其中一个项目的值。

使用自定义插槽

使用 slot 属性来定制特定项目。

你将可以访问以下插槽

  • #{{ item.slot }}
  • #{{ item.slot }}-leading
  • #{{ item.slot }}-label
  • #{{ item.slot }}-trailing
  • #{{ item.slot }}-content
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = [
  {
    label: 'Guide',
    icon: 'i-lucide-book-open'
  },
  {
    label: 'Composables',
    icon: 'i-lucide-database'
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    slot: 'components' as const
  }
] satisfies NavigationMenuItem[]
</script>

<template>
  <UNavigationMenu :items="items" class="w-full justify-center">
    <template #components-trailing>
      <UBadge label="44" variant="subtle" size="sm" />
    </template>
  </UNavigationMenu>
</template>
你也可以使用 #item#item-leading#item-label#item-trailing#item-content 插槽来定制所有项目。

使用内容插槽

使用 #item-content 插槽或 slot 属性 (#{{ item.slot }}-content) 来定制特定项目的内容。

<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'

const items = [
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    slot: 'docs' as const,
    children: [
      {
        label: 'Icons',
        description: 'You have nothing to do, @nuxt/icon will handle it automatically.'
      },
      {
        label: 'Colors',
        description: 'Choose a primary and a neutral color from your Tailwind CSS theme.'
      },
      {
        label: 'Theme',
        description: 'You can customize components by using the `class` / `ui` props or in your app.config.ts.'
      }
    ]
  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    slot: 'components' as const,
    children: [
      {
        label: 'Link',
        description: 'Use NuxtLink with superpowers.'
      },
      {
        label: 'Modal',
        description: 'Display a modal within your application.'
      },
      {
        label: 'NavigationMenu',
        description: 'Display a list of links.'
      },
      {
        label: 'Pagination',
        description: 'Display a list of pages.'
      },
      {
        label: 'Popover',
        description: 'Display a non-modal dialog that floats around a trigger element.'
      },
      {
        label: 'Progress',
        description: 'Show a horizontal bar to indicate task progression.'
      }
    ]
  },
  {
    label: 'GitHub',
    icon: 'i-simple-icons-github'
  }
] satisfies NavigationMenuItem[]
</script>

<template>
  <UNavigationMenu
    :items="items"
    class="w-full justify-center"
    :ui="{
      viewport: 'sm:w-(--reka-navigation-menu-viewport-width)',
      childList: 'sm:w-96',
      childLinkDescription: 'text-balance line-clamp-2'
    }"
  >
    <template #docs-content="{ item }">
      <ul class="grid gap-2 p-4 lg:w-[500px] lg:grid-cols-[minmax(0,.75fr)_minmax(0,1fr)]">
        <li class="row-span-3">
          <Placeholder class="size-full min-h-48" />
        </li>

        <li v-for="child in item.children" :key="child.label">
          <ULink class="text-sm text-left rounded-md p-3 transition-colors hover:bg-elevated/50">
            <p class="font-medium text-highlighted">
              {{ child.label }}
            </p>
            <p class="text-muted line-clamp-2">
              {{ child.description }}
            </p>
          </ULink>
        </li>
      </ul>
    </template>
  </UNavigationMenu>
</template>
在此示例中,我们在 viewport 上添加 sm:w-(--reka-navigation-menu-viewport-width) 类以实现动态宽度。这要求为内容的第一个子元素设置宽度。

API

属性

属性默认值类型
as

'div'

any

此组件应渲染为的元素或组件。

trailingIcon

appConfig.ui.icons.chevronDown

string

用于打开菜单的图标。

externalIcon

true

string | false | true

当项目是外部链接时显示的图标。设置为 false 以隐藏外部图标。

items

NavigationMenuItem[] | NavigationMenuItem[][]

颜色

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral"

variant

'pill'

"pill" | "link"

orientation

'horizontal'

"horizontal" | "vertical"

菜单的方向。

collapsed

false

boolean

折叠导航菜单以仅显示图标。仅当 orientationvertical 时有效。

highlight

boolean

在当前激活项旁边显示一条线。

高亮颜色

'primary'

"error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral"

content

NavigationMenuContentProps & Partial<EmitsToProps<DismissableLayerEmits>>

菜单的内容。

contentOrientation

'horizontal'

"horizontal" | "vertical"

内容的方向。仅当 orientationhorizontal 时有效。

arrow

false

boolean

在菜单旁显示箭头。

labelKey

'label'

string | number

用于从项中获取标签的键。

modelValue

string

要激活的菜单项的受控值。可用作 v-model

defaultValue

string

初次渲染时应激活的菜单项的值。

当您不需要控制值状态时使用。

delayDuration

0

number

指针进入触发器到工具提示打开的持续时间。

disableClickTrigger

false

boolean

如果为 true,则菜单不能通过点击触发器打开。

disableHoverTrigger

false

boolean

如果为 true,则菜单不能通过悬停触发器打开。

skipDelayDuration

300

number

用户进入另一个触发器而不会再次产生延迟的时间。

disablePointerLeaveClose

false

boolean

如果为 true,则菜单在指针离开事件期间不会关闭。

unmountOnHide

true

boolean

当为 true 时,元素将在关闭状态时被卸载。

ui

{ root?: ClassNameValue; list?: ClassNameValue; label?: ClassNameValue; item?: ClassNameValue; link?: ClassNameValue; ... 22 more ...; arrow?: ClassNameValue; }

插槽 (Slots)

插槽 (Slot)类型
item

{ item: NavigationMenuItem; index: number; active?: boolean | undefined; }

item-leading

{ item: NavigationMenuItem; index: number; active?: boolean | undefined; }

item-label

{ item: NavigationMenuItem; index: number; active?: boolean | undefined; }

item-trailing

{ item: NavigationMenuItem; index: number; active?: boolean | undefined; }

item-content

{ item: NavigationMenuItem; index: number; active?: boolean | undefined; }

list-leading

{}

list-trailing

{}

事件 (Emits)

事件 (Event)类型
update:modelValue

[value: string]

主题

app.config.ts
export default defineAppConfig({
  ui: {
    navigationMenu: {
      slots: {
        root: 'relative flex gap-1.5 [&>div]:min-w-0',
        list: 'isolate min-w-0',
        label: 'w-full flex items-center gap-1.5 font-semibold text-xs/5 text-highlighted px-2.5 py-1.5',
        item: 'min-w-0',
        link: 'group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2',
        linkLeadingIcon: 'shrink-0 size-5',
        linkLeadingAvatar: 'shrink-0',
        linkLeadingAvatarSize: '2xs',
        linkTrailing: 'ms-auto inline-flex gap-1.5 items-center',
        linkTrailingBadge: 'shrink-0',
        linkTrailingBadgeSize: 'sm',
        linkTrailingIcon: 'size-5 transform shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
        linkLabel: 'truncate',
        linkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
        childList: '',
        childItem: '',
        childLink: 'group size-full px-3 py-2 rounded-md flex items-start gap-2 text-start',
        childLinkWrapper: 'flex flex-col items-start',
        childLinkIcon: 'size-5 shrink-0',
        childLinkLabel: 'font-semibold text-sm relative inline-flex',
        childLinkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
        childLinkDescription: 'text-sm text-muted',
        separator: 'px-2 h-px bg-border',
        viewportWrapper: 'absolute top-full left-0 flex w-full',
        viewport: 'relative overflow-hidden bg-default shadow-lg rounded-md ring ring-default h-(--reka-navigation-menu-viewport-height) w-full transition-[width,height,left] duration-200 origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] z-[1]',
        content: 'absolute top-0 left-0 w-full sm:w-auto',
        indicator: 'absolute data-[state=visible]:animate-[fade-in_100ms_ease-out] data-[state=hidden]:animate-[fade-out_100ms_ease-in] data-[state=hidden]:opacity-0 bottom-0 z-[2] w-(--reka-navigation-menu-indicator-size) translate-x-(--reka-navigation-menu-indicator-position) flex h-2.5 items-end justify-center overflow-hidden transition-[translate,width] duration-200',
        arrow: 'relative top-[50%] size-2.5 rotate-45 border border-default bg-default z-[1] rounded-xs'
      },
      variants: {
        color: {
          primary: {
            link: 'focus-visible:before:ring-primary',
            childLink: 'focus-visible:outline-primary'
          },
          secondary: {
            link: 'focus-visible:before:ring-secondary',
            childLink: 'focus-visible:outline-secondary'
          },
          success: {
            link: 'focus-visible:before:ring-success',
            childLink: 'focus-visible:outline-success'
          },
          info: {
            link: 'focus-visible:before:ring-info',
            childLink: 'focus-visible:outline-info'
          },
          warning: {
            link: 'focus-visible:before:ring-warning',
            childLink: 'focus-visible:outline-warning'
          },
          error: {
            link: 'focus-visible:before:ring-error',
            childLink: 'focus-visible:outline-error'
          },
          neutral: {
            link: 'focus-visible:before:ring-inverted',
            childLink: 'focus-visible:outline-inverted'
          }
        },
        highlightColor: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          pill: '',
          link: ''
        },
        orientation: {
          horizontal: {
            root: 'items-center justify-between',
            list: 'flex items-center',
            item: 'py-2',
            link: 'px-2.5 py-1.5 before:inset-x-px before:inset-y-0',
            childList: 'grid p-2'
          },
          vertical: {
            root: 'flex-col',
            link: 'flex-row px-2.5 py-1.5 before:inset-y-px before:inset-x-0'
          }
        },
        contentOrientation: {
          horizontal: {
            viewportWrapper: 'justify-center',
            content: 'data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]'
          },
          vertical: {
            viewport: 'sm:w-(--reka-navigation-menu-viewport-width) left-(--reka-navigation-menu-viewport-left)'
          }
        },
        active: {
          true: {
            childLink: 'bg-elevated text-highlighted',
            childLinkIcon: 'text-default'
          },
          false: {
            link: 'text-muted',
            linkLeadingIcon: 'text-dimmed',
            childLink: [
              'hover:bg-elevated/50 text-default hover:text-highlighted',
              'transition-colors'
            ],
            childLinkIcon: [
              'text-dimmed group-hover:text-default',
              'transition-colors'
            ]
          }
        },
        disabled: {
          true: {
            link: 'cursor-not-allowed opacity-75'
          }
        },
        highlight: {
          true: ''
        },
        level: {
          true: ''
        },
        collapsed: {
          true: ''
        }
      },
      compoundVariants: [
        {
          orientation: 'horizontal',
          contentOrientation: 'horizontal',
          class: {
            childList: 'grid-cols-2 gap-2'
          }
        },
        {
          orientation: 'horizontal',
          contentOrientation: 'vertical',
          class: {
            childList: 'gap-1',
            content: 'w-60'
          }
        },
        {
          orientation: 'horizontal',
          highlight: true,
          class: {
            link: [
              'after:absolute after:-bottom-2 after:inset-x-2.5 after:block after:h-px after:rounded-full',
              'after:transition-colors'
            ]
          }
        },
        {
          orientation: 'vertical',
          highlight: true,
          level: true,
          class: {
            link: [
              'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full',
              'after:transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'pill',
          class: {
            link: [
              'hover:text-highlighted hover:before:bg-elevated/50',
              'transition-colors before:transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-default',
              'transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'pill',
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:text-highlighted',
            linkLeadingIcon: 'group-data-[state=open]:text-default'
          }
        },
        {
          disabled: false,
          variant: 'pill',
          highlight: true,
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:before:bg-elevated/50'
          }
        },
        {
          disabled: false,
          variant: 'pill',
          highlight: false,
          active: false,
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:before:bg-elevated/50'
          }
        },
        {
          color: 'primary',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-primary',
            linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-highlighted',
            linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: false,
          class: {
            link: 'before:bg-elevated'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: true,
          class: {
            link: [
              'hover:before:bg-elevated/50',
              'before:transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'link',
          class: {
            link: [
              'hover:text-highlighted',
              'transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-default',
              'transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'link',
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:text-highlighted',
            linkLeadingIcon: 'group-data-[state=open]:text-default'
          }
        },
        {
          color: 'primary',
          variant: 'link',
          active: true,
          class: {
            link: 'text-primary',
            linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
          }
        },
        {
          color: 'neutral',
          variant: 'link',
          active: true,
          class: {
            link: 'text-highlighted',
            linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
          }
        },
        {
          highlightColor: 'primary',
          highlight: true,
          level: true,
          active: true,
          class: {
            link: 'after:bg-primary'
          }
        },
        {
          highlightColor: 'neutral',
          highlight: true,
          level: true,
          active: true,
          class: {
            link: 'after:bg-inverted'
          }
        },
        {
          orientation: 'vertical',
          collapsed: false,
          class: {
            childList: 'ms-5 border-s border-default',
            childItem: 'ps-1.5 -ms-px'
          }
        },
        {
          orientation: 'vertical',
          collapsed: true,
          class: {
            link: 'px-1.5'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        highlightColor: 'primary',
        variant: 'pill'
      }
    }
  }
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import ui from '@nuxt/ui/vite'

export default defineConfig({
  plugins: [
    vue(),
    ui({
      ui: {
        navigationMenu: {
          slots: {
            root: 'relative flex gap-1.5 [&>div]:min-w-0',
            list: 'isolate min-w-0',
            label: 'w-full flex items-center gap-1.5 font-semibold text-xs/5 text-highlighted px-2.5 py-1.5',
            item: 'min-w-0',
            link: 'group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2',
            linkLeadingIcon: 'shrink-0 size-5',
            linkLeadingAvatar: 'shrink-0',
            linkLeadingAvatarSize: '2xs',
            linkTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            linkTrailingBadge: 'shrink-0',
            linkTrailingBadgeSize: 'sm',
            linkTrailingIcon: 'size-5 transform shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
            linkLabel: 'truncate',
            linkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
            childList: '',
            childItem: '',
            childLink: 'group size-full px-3 py-2 rounded-md flex items-start gap-2 text-start',
            childLinkWrapper: 'flex flex-col items-start',
            childLinkIcon: 'size-5 shrink-0',
            childLinkLabel: 'font-semibold text-sm relative inline-flex',
            childLinkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
            childLinkDescription: 'text-sm text-muted',
            separator: 'px-2 h-px bg-border',
            viewportWrapper: 'absolute top-full left-0 flex w-full',
            viewport: 'relative overflow-hidden bg-default shadow-lg rounded-md ring ring-default h-(--reka-navigation-menu-viewport-height) w-full transition-[width,height,left] duration-200 origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] z-[1]',
            content: 'absolute top-0 left-0 w-full sm:w-auto',
            indicator: 'absolute data-[state=visible]:animate-[fade-in_100ms_ease-out] data-[state=hidden]:animate-[fade-out_100ms_ease-in] data-[state=hidden]:opacity-0 bottom-0 z-[2] w-(--reka-navigation-menu-indicator-size) translate-x-(--reka-navigation-menu-indicator-position) flex h-2.5 items-end justify-center overflow-hidden transition-[translate,width] duration-200',
            arrow: 'relative top-[50%] size-2.5 rotate-45 border border-default bg-default z-[1] rounded-xs'
          },
          variants: {
            color: {
              primary: {
                link: 'focus-visible:before:ring-primary',
                childLink: 'focus-visible:outline-primary'
              },
              secondary: {
                link: 'focus-visible:before:ring-secondary',
                childLink: 'focus-visible:outline-secondary'
              },
              success: {
                link: 'focus-visible:before:ring-success',
                childLink: 'focus-visible:outline-success'
              },
              info: {
                link: 'focus-visible:before:ring-info',
                childLink: 'focus-visible:outline-info'
              },
              warning: {
                link: 'focus-visible:before:ring-warning',
                childLink: 'focus-visible:outline-warning'
              },
              error: {
                link: 'focus-visible:before:ring-error',
                childLink: 'focus-visible:outline-error'
              },
              neutral: {
                link: 'focus-visible:before:ring-inverted',
                childLink: 'focus-visible:outline-inverted'
              }
            },
            highlightColor: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            variant: {
              pill: '',
              link: ''
            },
            orientation: {
              horizontal: {
                root: 'items-center justify-between',
                list: 'flex items-center',
                item: 'py-2',
                link: 'px-2.5 py-1.5 before:inset-x-px before:inset-y-0',
                childList: 'grid p-2'
              },
              vertical: {
                root: 'flex-col',
                link: 'flex-row px-2.5 py-1.5 before:inset-y-px before:inset-x-0'
              }
            },
            contentOrientation: {
              horizontal: {
                viewportWrapper: 'justify-center',
                content: 'data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]'
              },
              vertical: {
                viewport: 'sm:w-(--reka-navigation-menu-viewport-width) left-(--reka-navigation-menu-viewport-left)'
              }
            },
            active: {
              true: {
                childLink: 'bg-elevated text-highlighted',
                childLinkIcon: 'text-default'
              },
              false: {
                link: 'text-muted',
                linkLeadingIcon: 'text-dimmed',
                childLink: [
                  'hover:bg-elevated/50 text-default hover:text-highlighted',
                  'transition-colors'
                ],
                childLinkIcon: [
                  'text-dimmed group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            disabled: {
              true: {
                link: 'cursor-not-allowed opacity-75'
              }
            },
            highlight: {
              true: ''
            },
            level: {
              true: ''
            },
            collapsed: {
              true: ''
            }
          },
          compoundVariants: [
            {
              orientation: 'horizontal',
              contentOrientation: 'horizontal',
              class: {
                childList: 'grid-cols-2 gap-2'
              }
            },
            {
              orientation: 'horizontal',
              contentOrientation: 'vertical',
              class: {
                childList: 'gap-1',
                content: 'w-60'
              }
            },
            {
              orientation: 'horizontal',
              highlight: true,
              class: {
                link: [
                  'after:absolute after:-bottom-2 after:inset-x-2.5 after:block after:h-px after:rounded-full',
                  'after:transition-colors'
                ]
              }
            },
            {
              orientation: 'vertical',
              highlight: true,
              level: true,
              class: {
                link: [
                  'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full',
                  'after:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'pill',
              class: {
                link: [
                  'hover:text-highlighted hover:before:bg-elevated/50',
                  'transition-colors before:transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'pill',
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:text-highlighted',
                linkLeadingIcon: 'group-data-[state=open]:text-default'
              }
            },
            {
              disabled: false,
              variant: 'pill',
              highlight: true,
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:before:bg-elevated/50'
              }
            },
            {
              disabled: false,
              variant: 'pill',
              highlight: false,
              active: false,
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:before:bg-elevated/50'
              }
            },
            {
              color: 'primary',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: false,
              class: {
                link: 'before:bg-elevated'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: true,
              class: {
                link: [
                  'hover:before:bg-elevated/50',
                  'before:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'link',
              class: {
                link: [
                  'hover:text-highlighted',
                  'transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'link',
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:text-highlighted',
                linkLeadingIcon: 'group-data-[state=open]:text-default'
              }
            },
            {
              color: 'primary',
              variant: 'link',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'link',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              highlightColor: 'primary',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-primary'
              }
            },
            {
              highlightColor: 'neutral',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-inverted'
              }
            },
            {
              orientation: 'vertical',
              collapsed: false,
              class: {
                childList: 'ms-5 border-s border-default',
                childItem: 'ps-1.5 -ms-px'
              }
            },
            {
              orientation: 'vertical',
              collapsed: true,
              class: {
                link: 'px-1.5'
              }
            }
          ],
          defaultVariants: {
            color: 'primary',
            highlightColor: 'primary',
            variant: 'pill'
          }
        }
      }
    })
  ]
})
vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import uiPro from '@nuxt/ui-pro/vite'

export default defineConfig({
  plugins: [
    vue(),
    uiPro({
      ui: {
        navigationMenu: {
          slots: {
            root: 'relative flex gap-1.5 [&>div]:min-w-0',
            list: 'isolate min-w-0',
            label: 'w-full flex items-center gap-1.5 font-semibold text-xs/5 text-highlighted px-2.5 py-1.5',
            item: 'min-w-0',
            link: 'group relative w-full flex items-center gap-1.5 font-medium text-sm before:absolute before:z-[-1] before:rounded-md focus:outline-none focus-visible:outline-none dark:focus-visible:outline-none focus-visible:before:ring-inset focus-visible:before:ring-2',
            linkLeadingIcon: 'shrink-0 size-5',
            linkLeadingAvatar: 'shrink-0',
            linkLeadingAvatarSize: '2xs',
            linkTrailing: 'ms-auto inline-flex gap-1.5 items-center',
            linkTrailingBadge: 'shrink-0',
            linkTrailingBadgeSize: 'sm',
            linkTrailingIcon: 'size-5 transform shrink-0 group-data-[state=open]:rotate-180 transition-transform duration-200',
            linkLabel: 'truncate',
            linkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
            childList: '',
            childItem: '',
            childLink: 'group size-full px-3 py-2 rounded-md flex items-start gap-2 text-start',
            childLinkWrapper: 'flex flex-col items-start',
            childLinkIcon: 'size-5 shrink-0',
            childLinkLabel: 'font-semibold text-sm relative inline-flex',
            childLinkLabelExternalIcon: 'inline-block size-3 align-top text-dimmed',
            childLinkDescription: 'text-sm text-muted',
            separator: 'px-2 h-px bg-border',
            viewportWrapper: 'absolute top-full left-0 flex w-full',
            viewport: 'relative overflow-hidden bg-default shadow-lg rounded-md ring ring-default h-(--reka-navigation-menu-viewport-height) w-full transition-[width,height,left] duration-200 origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in] z-[1]',
            content: 'absolute top-0 left-0 w-full sm:w-auto',
            indicator: 'absolute data-[state=visible]:animate-[fade-in_100ms_ease-out] data-[state=hidden]:animate-[fade-out_100ms_ease-in] data-[state=hidden]:opacity-0 bottom-0 z-[2] w-(--reka-navigation-menu-indicator-size) translate-x-(--reka-navigation-menu-indicator-position) flex h-2.5 items-end justify-center overflow-hidden transition-[translate,width] duration-200',
            arrow: 'relative top-[50%] size-2.5 rotate-45 border border-default bg-default z-[1] rounded-xs'
          },
          variants: {
            color: {
              primary: {
                link: 'focus-visible:before:ring-primary',
                childLink: 'focus-visible:outline-primary'
              },
              secondary: {
                link: 'focus-visible:before:ring-secondary',
                childLink: 'focus-visible:outline-secondary'
              },
              success: {
                link: 'focus-visible:before:ring-success',
                childLink: 'focus-visible:outline-success'
              },
              info: {
                link: 'focus-visible:before:ring-info',
                childLink: 'focus-visible:outline-info'
              },
              warning: {
                link: 'focus-visible:before:ring-warning',
                childLink: 'focus-visible:outline-warning'
              },
              error: {
                link: 'focus-visible:before:ring-error',
                childLink: 'focus-visible:outline-error'
              },
              neutral: {
                link: 'focus-visible:before:ring-inverted',
                childLink: 'focus-visible:outline-inverted'
              }
            },
            highlightColor: {
              primary: '',
              secondary: '',
              success: '',
              info: '',
              warning: '',
              error: '',
              neutral: ''
            },
            variant: {
              pill: '',
              link: ''
            },
            orientation: {
              horizontal: {
                root: 'items-center justify-between',
                list: 'flex items-center',
                item: 'py-2',
                link: 'px-2.5 py-1.5 before:inset-x-px before:inset-y-0',
                childList: 'grid p-2'
              },
              vertical: {
                root: 'flex-col',
                link: 'flex-row px-2.5 py-1.5 before:inset-y-px before:inset-x-0'
              }
            },
            contentOrientation: {
              horizontal: {
                viewportWrapper: 'justify-center',
                content: 'data-[motion=from-start]:animate-[enter-from-left_200ms_ease] data-[motion=from-end]:animate-[enter-from-right_200ms_ease] data-[motion=to-start]:animate-[exit-to-left_200ms_ease] data-[motion=to-end]:animate-[exit-to-right_200ms_ease]'
              },
              vertical: {
                viewport: 'sm:w-(--reka-navigation-menu-viewport-width) left-(--reka-navigation-menu-viewport-left)'
              }
            },
            active: {
              true: {
                childLink: 'bg-elevated text-highlighted',
                childLinkIcon: 'text-default'
              },
              false: {
                link: 'text-muted',
                linkLeadingIcon: 'text-dimmed',
                childLink: [
                  'hover:bg-elevated/50 text-default hover:text-highlighted',
                  'transition-colors'
                ],
                childLinkIcon: [
                  'text-dimmed group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            disabled: {
              true: {
                link: 'cursor-not-allowed opacity-75'
              }
            },
            highlight: {
              true: ''
            },
            level: {
              true: ''
            },
            collapsed: {
              true: ''
            }
          },
          compoundVariants: [
            {
              orientation: 'horizontal',
              contentOrientation: 'horizontal',
              class: {
                childList: 'grid-cols-2 gap-2'
              }
            },
            {
              orientation: 'horizontal',
              contentOrientation: 'vertical',
              class: {
                childList: 'gap-1',
                content: 'w-60'
              }
            },
            {
              orientation: 'horizontal',
              highlight: true,
              class: {
                link: [
                  'after:absolute after:-bottom-2 after:inset-x-2.5 after:block after:h-px after:rounded-full',
                  'after:transition-colors'
                ]
              }
            },
            {
              orientation: 'vertical',
              highlight: true,
              level: true,
              class: {
                link: [
                  'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full',
                  'after:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'pill',
              class: {
                link: [
                  'hover:text-highlighted hover:before:bg-elevated/50',
                  'transition-colors before:transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'pill',
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:text-highlighted',
                linkLeadingIcon: 'group-data-[state=open]:text-default'
              }
            },
            {
              disabled: false,
              variant: 'pill',
              highlight: true,
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:before:bg-elevated/50'
              }
            },
            {
              disabled: false,
              variant: 'pill',
              highlight: false,
              active: false,
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:before:bg-elevated/50'
              }
            },
            {
              color: 'primary',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'pill',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: false,
              class: {
                link: 'before:bg-elevated'
              }
            },
            {
              variant: 'pill',
              active: true,
              highlight: true,
              class: {
                link: [
                  'hover:before:bg-elevated/50',
                  'before:transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'link',
              class: {
                link: [
                  'hover:text-highlighted',
                  'transition-colors'
                ],
                linkLeadingIcon: [
                  'group-hover:text-default',
                  'transition-colors'
                ]
              }
            },
            {
              disabled: false,
              active: false,
              variant: 'link',
              orientation: 'horizontal',
              class: {
                link: 'data-[state=open]:text-highlighted',
                linkLeadingIcon: 'group-data-[state=open]:text-default'
              }
            },
            {
              color: 'primary',
              variant: 'link',
              active: true,
              class: {
                link: 'text-primary',
                linkLeadingIcon: 'text-primary group-data-[state=open]:text-primary'
              }
            },
            {
              color: 'neutral',
              variant: 'link',
              active: true,
              class: {
                link: 'text-highlighted',
                linkLeadingIcon: 'text-highlighted group-data-[state=open]:text-highlighted'
              }
            },
            {
              highlightColor: 'primary',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-primary'
              }
            },
            {
              highlightColor: 'neutral',
              highlight: true,
              level: true,
              active: true,
              class: {
                link: 'after:bg-inverted'
              }
            },
            {
              orientation: 'vertical',
              collapsed: false,
              class: {
                childList: 'ms-5 border-s border-default',
                childItem: 'ps-1.5 -ms-px'
              }
            },
            {
              orientation: 'vertical',
              collapsed: true,
              class: {
                link: 'px-1.5'
              }
            }
          ],
          defaultVariants: {
            color: 'primary',
            highlightColor: 'primary',
            variant: 'pill'
          }
        }
      }
    })
  ]
})
为提高可读性,省略了 compoundVariants 中的部分颜色。请查看 GitHub 上的源代码。