NavigationMenu

A list of links that can be displayed horizontally or vertically.

Usage

Items

Use the items prop as an array of objects with the following properties:

  • label?: string
  • icon?: string
  • avatar?: AvatarProps
  • badge?: string | number | BadgeProps
  • trailingIcon?: string
  • value?: string
  • disabled?: boolean
  • class?: any
  • slot?: string
  • onSelect?(e: Event): void

You can also pass any property from the Link component such as to, target, etc.

<script setup lang="ts">
const items = ref([
  {
    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: 'useModal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/composables/use-modal'
      },
      {
        label: 'useSlideover',
        icon: 'i-lucide-file-text',
        description: 'Display a slideover within your application.',
        to: '/composables/use-slideover'
      },
      {
        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="justify-center" />
</template>
You can pass an array of arrays to the items prop to display groups of items.
Each item can take a children array of objects with the following properties to create submenus:
  • label: string
  • description?: string
  • icon?: string
  • class?: any
  • onSelect?(e: Event): void

Orientation

Use the orientation prop to change the orientation of the NavigationMenu.

When orientation is vertical, a Collapsible component is used to display children. You can control the open state of each item using the open and defaultOpen properties.

<script setup lang="ts">
const items = ref([
  [
    {
      label: 'Guide',
      icon: 'i-lucide-book-open',
      defaultOpen: true,
      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: 'useModal',
          icon: 'i-lucide-file-text',
          description: 'Display a modal within your application.',
          to: '/composables/use-modal'
        },
        {
          label: 'useSlideover',
          icon: 'i-lucide-file-text',
          description: 'Display a slideover within your application.',
          to: '/composables/use-slideover'
        },
        {
          label: 'useToast',
          icon: 'i-lucide-file-text',
          description: 'Display a toast within your application.',
          to: '/composables/use-toast'
        }
      ]
    },
    {
      label: 'Components',
      icon: 'i-lucide-box',
      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 orientation="vertical" :items="items" class="data-[orientation=vertical]:w-48" />
</template>
Groups will be spaced when orientation is horizontal and separated when orientation is vertical.

Highlight

Use the highlight prop to display a highlighted border for the active item.

Use the highlight-color prop to change the color of the border. It defaults to the color prop.

<script setup lang="ts">
const items = ref([
  [
    {
      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
    highlight
    orientation="horizontal"
    :items="items"
    class="data-[orientation=horizontal]:border-b data-[orientation=vertical]:border-l border-[var(--ui-border)]"
  />
</template>
In this example, the border-l and border-b classes are applied to display a border, this is not done by default to let you have a clean slate to work with.

Color

Use the color prop to change the color of the NavigationMenu.

<script setup lang="ts">
const items = ref([
  [
    {
      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" />
</template>

Variant

Use the variant prop to change the variant of the NavigationMenu.

<script setup lang="ts">
const items = ref([
  [
    {
      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" />
</template>
The highlight prop changes the pill variant active item style. Try it out to see the difference.

Trailing Icon

Use the trailing-icon prop to customize the trailing Icon of each item. Defaults to i-lucide-chevron-down. This icon is only displayed when an item has children.

You can also set an icon for a specific item by using the trailingIcon property in the item object.
<script setup lang="ts">
const items = ref([
  {
    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: 'useModal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/composables/use-modal'
      },
      {
        label: 'useSlideover',
        icon: 'i-lucide-file-text',
        description: 'Display a slideover within your application.',
        to: '/composables/use-slideover'
      },
      {
        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="justify-center" />
</template>
You can customize this icon globally in your app.config.ts under ui.icons.chevronDown key.

Arrow

Use the arrow prop to display an arrow on the NavigationMenu content when items have children.

<script setup lang="ts">
const items = ref([
  {
    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: 'useModal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.',
        to: '/composables/use-modal'
      },
      {
        label: 'useSlideover',
        icon: 'i-lucide-file-text',
        description: 'Display a slideover within your application.',
        to: '/composables/use-slideover'
      },
      {
        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="justify-center" />
</template>
The arrow is animated to follow the active item.

Examples

Control active item

You can control the active item by using the default-value prop or the v-model directive with the index of the item.

<script setup lang="ts">
const items = [
  {
    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: 'useModal',
        icon: 'i-lucide-file-text',
        description: 'Display a modal within your application.'
      },
      {
        label: 'useSlideover',
        icon: 'i-lucide-file-text',
        description: 'Display a 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="justify-center" />
</template>
In this example, leveraging defineShortcuts, you can switch the active item by pressing 1, 2, or 3.
You can also pass the value of one of the items if provided.

With custom slot

Use the slot property to customize a specific item.

You will have access to the following slots:

  • #{{ item.slot }}
  • #{{ item.slot }}-leading
  • #{{ item.slot }}-label
  • #{{ item.slot }}-trailing
  • #{{ item.slot }}-content
<script setup lang="ts">
const items = [
  {
    label: 'Guide',
    icon: 'i-lucide-book-open'

  },
  {
    label: 'Composables',
    icon: 'i-lucide-database'

  },
  {
    label: 'Components',
    icon: 'i-lucide-box',
    slot: 'components'
  }
]
</script>

<template>
  <UNavigationMenu :items="items" class="justify-center">
    <template #components-trailing>
      <UBadge label="44" variant="subtle" size="sm" />
    </template>
  </UNavigationMenu>
</template>
You can also use the #item, #item-leading, #item-label, #item-trailing and #item-content slots to customize all items.

With content slot

Use the #item-content slot or the slot property (#{{ item.slot }}-content) to customize the content of a specific item.

<script setup lang="ts">
const items = [
  {
    label: 'Docs',
    icon: 'i-lucide-book-open',
    slot: 'docs',
    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',
    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'
  }
]
</script>

<template>
  <UNavigationMenu
    :items="items"
    class="justify-center"
    :ui="{
      viewport: 'sm:w-[var(--radix-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-[var(--ui-bg-elevated)]/50">
            <p class="font-medium text-[var(--ui-text-highlighted)]">
              {{ child.label }}
            </p>
            <p class="text-[var(--ui-text-muted)] line-clamp-2">
              {{ child.description }}
            </p>
          </ULink>
        </li>
      </ul>
    </template>
  </UNavigationMenu>
</template>
In this example, we add the sm:w-[var(--radix-navigation-menu-viewport-width)] class on the viewport to have a dynamic width. This requires to set a width on the content's first child.

API

Props

Prop Default Type
as

'div'

any

The element or component this component should render as.

trailingIcon

appConfig.ui.icons.chevronDown

string

The icon displayed to open the menu.

items

NavigationMenuItem[] | NavigationMenuItem[][]

color

primary

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

variant

pill

"link" | "pill"

orientation

"horizontal"

"horizontal" | "vertical"

The orientation of the menu.

highlight

boolean

Display a line next to the active item.

highlightColor

primary

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

content

NavigationMenuContentProps

The content of the menu.

arrow

false

boolean

Display an arrow alongside the menu.

labelKey

"label"

string

The key used to get the label from the item.

defaultValue

string

The value of the menu item that should be active when initially rendered.

Use when you do not need to control the value state.

modelValue

string

The controlled value of the menu item to activate. Can be used as v-model.

delayDuration

0

number

The duration from when the pointer enters the trigger until the tooltip gets opened.

skipDelayDuration

300

number

How much time a user has to enter another trigger without incurring a delay again.

disableClickTrigger

false

boolean

If true, menu cannot be open by click on trigger

disableHoverTrigger

false

boolean

If true, menu cannot be open by hover on trigger

ui

PartialString<{ root: string; list: string; item: string; link: string; linkLeadingIcon: string; linkLeadingAvatar: string; linkLeadingAvatarSize: string; linkTrailing: string; linkTrailingBadge: string; ... 17 more ...; arrow: string; }>

Slots

Slot Type
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; }

Emits

Event Type
update:modelValue

[value: string]

Theme

app.config.ts
export default defineAppConfig({
  ui: {
    navigationMenu: {
      slots: {
        root: 'relative flex gap-1.5 [&>div]:min-w-0',
        list: 'isolate min-w-0',
        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-[calc(var(--ui-radius)*1.5)] 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',
        linkTrailingBadge: 'shrink-0 rounded-[calc(var(--ui-radius)]',
        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-[var(--ui-text-dimmed)]',
        childList: '',
        childItem: '',
        childLink: 'group size-full px-3 py-2 rounded-[calc(var(--ui-radius)*1.5)] 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-[var(--ui-text-dimmed)]',
        childLinkDescription: 'text-sm text-[var(--ui-text-muted)]',
        separator: 'px-2 h-px bg-[var(--ui-border)]',
        viewportWrapper: 'absolute top-full left-0 flex w-full justify-center',
        viewport: 'relative overflow-hidden bg-[var(--ui-bg)] shadow-lg rounded-[calc(var(--ui-radius)*1.5)] ring ring-[var(--ui-border)] h-[var(--radix-navigation-menu-viewport-height)] w-full transition-[width,height] origin-[top_center] data-[state=open]:animate-[scale-in_100ms_ease-out] data-[state=closed]:animate-[scale-out_100ms_ease-in]',
        content: 'absolute top-0 left-0 w-full 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]',
        indicator: 'data-[state=visible]:animate-[fade-in_100ms_ease-out] data-[state=hidden]:animate-[fade-out_100ms_ease-in] bottom-0 z-[1] flex h-2.5 items-end justify-center overflow-hidden transition-transform duration-200 ease-out',
        arrow: 'relative top-[50%] size-2.5 rotate-45 border border-[var(--ui-border)] bg-[var(--ui-bg)] z-[1] rounded-[calc(var(--ui-radius)/2)]'
      },
      variants: {
        color: {
          primary: {
            link: 'focus-visible:before:ring-[var(--ui-primary)]',
            childLink: 'focus-visible:outline-[var(--ui-primary)]'
          },
          secondary: {
            link: 'focus-visible:before:ring-[var(--ui-secondary)]',
            childLink: 'focus-visible:outline-[var(--ui-secondary)]'
          },
          success: {
            link: 'focus-visible:before:ring-[var(--ui-success)]',
            childLink: 'focus-visible:outline-[var(--ui-success)]'
          },
          info: {
            link: 'focus-visible:before:ring-[var(--ui-info)]',
            childLink: 'focus-visible:outline-[var(--ui-info)]'
          },
          warning: {
            link: 'focus-visible:before:ring-[var(--ui-warning)]',
            childLink: 'focus-visible:outline-[var(--ui-warning)]'
          },
          error: {
            link: 'focus-visible:before:ring-[var(--ui-error)]',
            childLink: 'focus-visible:outline-[var(--ui-error)]'
          },
          neutral: {
            link: 'focus-visible:before:ring-[var(--ui-border-inverted)]',
            childLink: 'focus-visible:outline-[var(--ui-border-inverted)]'
          }
        },
        highlightColor: {
          primary: '',
          secondary: '',
          success: '',
          info: '',
          warning: '',
          error: '',
          neutral: ''
        },
        variant: {
          pill: '',
          link: ''
        },
        orientation: {
          horizontal: {
            root: 'w-full 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 grid-cols-2 gap-2 p-2'
          },
          vertical: {
            root: 'flex-col',
            link: 'flex-row px-2.5 py-1.5 before:inset-y-px before:inset-x-0',
            childList: 'ms-5 border-s border-[var(--ui-border)]',
            childItem: 'ps-1.5 -ms-px'
          }
        },
        active: {
          true: {
            childLink: 'bg-[var(--ui-bg-elevated)] text-[var(--ui-text-highlighted)]',
            childLinkIcon: 'text-[var(--ui-text)]'
          },
          false: {
            link: 'text-[var(--ui-text-muted)]',
            linkLeadingIcon: 'text-[var(--ui-text-dimmed)]',
            childLink: [
              'hover:bg-[var(--ui-bg-elevated)]/50 text-[var(--ui-text)] hover:text-[var(--ui-text-highlighted)]',
              'transition-colors'
            ],
            childLinkIcon: [
              'text-[var(--ui-text-dimmed)] group-hover:text-[var(--ui-text)]',
              'transition-colors'
            ]
          }
        },
        disabled: {
          true: {
            link: 'cursor-not-allowed opacity-75'
          }
        },
        highlight: {
          true: ''
        }
      },
      compoundVariants: [
        {
          highlight: true,
          orientation: 'horizontal',
          class: {
            item: '-mb-px',
            link: 'after:absolute after:-bottom-2 after:inset-x-2.5 after:block after:h-px after:rounded-full'
          }
        },
        {
          highlight: true,
          orientation: 'vertical',
          class: {
            item: 'px-1.5 -ms-px',
            link: 'after:absolute after:-start-1.5 after:inset-y-0.5 after:block after:w-px after:rounded-full'
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'pill',
          class: {
            link: [
              'hover:text-[var(--ui-text-highlighted)] hover:before:bg-[var(--ui-bg-elevated)]/50 data-[state=open]:text-[var(--ui-text-highlighted)]',
              'transition-colors before:transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-[var(--ui-text)] group-data-[state=open]:text-[var(--ui-text)]',
              'transition-colors'
            ]
          }
        },
        {
          disabled: false,
          variant: 'pill',
          highlight: true,
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:before:bg-[var(--ui-bg-elevated)]/50'
          }
        },
        {
          disabled: false,
          variant: 'pill',
          highlight: false,
          active: false,
          orientation: 'horizontal',
          class: {
            link: 'data-[state=open]:before:bg-[var(--ui-bg-elevated)]/50'
          }
        },
        {
          color: 'primary',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-[var(--ui-primary)]',
            linkLeadingIcon: 'text-[var(--ui-primary)]'
          }
        },
        {
          color: 'neutral',
          variant: 'pill',
          active: true,
          class: {
            link: 'text-[var(--ui-text-highlighted)]',
            linkLeadingIcon: 'text-[var(--ui-text-highlighted)]'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: false,
          class: {
            link: 'before:bg-[var(--ui-bg-elevated)]'
          }
        },
        {
          variant: 'pill',
          active: true,
          highlight: true,
          class: {
            link: [
              'hover:before:bg-[var(--ui-bg-elevated)]/50',
              'before:transition-colors'
            ]
          }
        },
        {
          disabled: false,
          active: false,
          variant: 'link',
          class: {
            link: [
              'hover:text-[var(--ui-text-highlighted)] data-[state=open]:text-[var(--ui-text-highlighted)]',
              'transition-colors'
            ],
            linkLeadingIcon: [
              'group-hover:text-[var(--ui-text)] group-data-[state=open]:text-[var(--ui-text)]',
              'transition-colors'
            ]
          }
        },
        {
          color: 'primary',
          variant: 'link',
          active: true,
          class: {
            link: 'text-[var(--ui-primary)]',
            linkLeadingIcon: 'text-[var(--ui-primary)]'
          }
        },
        {
          color: 'neutral',
          variant: 'link',
          active: true,
          class: {
            link: 'text-[var(--ui-text-highlighted)]',
            linkLeadingIcon: 'text-[var(--ui-text-highlighted)]'
          }
        },
        {
          highlightColor: 'primary',
          highlight: true,
          active: true,
          class: {
            link: 'after:bg-[var(--ui-primary)]'
          }
        },
        {
          highlightColor: 'neutral',
          highlight: true,
          active: true,
          class: {
            link: 'after:bg-[var(--ui-bg-inverted)]'
          }
        }
      ],
      defaultVariants: {
        color: 'primary',
        highlightColor: 'primary',
        variant: 'pill'
      }
    }
  }
})
Some colors in compoundVariants are omitted for readability. Check out the source code on GitHub.