Skip to content

Menu ​

A horizontal navigation bar for top-level page navigation. Supports dropdown submenus, badges, icons, themes, overflow handling, indicator bar, keyboard navigation, and more.

For vertical sidebar navigation, see Sidebar.

Basic ​

vue
<script setup>
import { ref } from 'vue'
import { VxMenu } from 'veloxui'

const active = ref('home')

const items = [
  { key: 'home', label: 'Home', icon: 'home' },
  { key: 'inbox', label: 'Inbox', icon: 'mail' },
  { key: 'starred', label: 'Starred', icon: 'star' },
  { key: 'settings', label: 'Settings', icon: 'settings' },
]
</script>

<template>
  <VxMenu v-model="active" :items="items" />
</template>

Borderless ​

Set :bordered="false" to remove the border and border-radius.

vue
<VxMenu v-model="active" :items="items" :bordered="false" />

Custom Sizing ​

Customize the menu border-radius, item border-radius, and item height.

vue
<VxMenu v-model="active" :items="items" :radius="20" :item-radius="16" :item-height="44" />
<!-- Fully rounded pill style -->
<VxMenu v-model="active" :items="items" :radius="999" :item-radius="999" />

With Badges ​

vue
<VxMenu v-model="active" :items="[
  { key: 'inbox', label: 'Inbox', icon: 'mail', badge: 12, badgeType: 'primary' },
  { key: 'starred', label: 'Starred', icon: 'star', badge: 'New', badgeType: 'success' },
  { key: 'alerts', label: 'Alerts', icon: 'heart', badge: 3, badgeType: 'danger' },
  { key: 'settings', label: 'Settings', icon: 'settings' },
]" />

Hover over a parent item to reveal its dropdown children. The parent highlights when a child is active.

vue
<VxMenu v-model="active" :items="[
  { key: 'home', label: 'Home', icon: 'home' },
  {
    key: 'projects',
    label: 'Projects',
    icon: 'folder',
    children: [
      { key: 'design', label: 'Design System' },
      { key: 'api', label: 'API Platform' },
    ],
  },
]" />

Notification Dots ​

Small colored indicators on items. Default red, customizable with dotColor.

vue
<VxMenu v-model="active" :items="[
  { key: 'inbox', label: 'Inbox', icon: 'mail', dot: true },
  { key: 'alerts', label: 'Alerts', icon: 'heart', dot: true, dotColor: '#f59e0b' },
]" />

Active Indicator Bar ​

Set indicator to show an animated bottom bar that slides to the active item.

vue
<VxMenu v-model="active" :items="items" indicator />

Sticky ​

Set sticky to pin the menu at the top of the scroll container.

vue
<VxMenu v-model="active" :items="items" sticky />

Overflow ​

When items don't fit, excess items collapse into a "More" dropdown.

vue
<VxMenu v-model="active" :items="items" overflow />

Loading ​

Show skeleton placeholders while data is being fetched.

vue
<VxMenu loading :loading-count="5" />

Slots ​

Use prefix and suffix slots to add content around items. Use the item slot to customize item rendering.

vue
<VxMenu v-model="active" :items="items">
  <template #prefix>
    <img src="/logo.svg" style="height: 24px; margin-right: 12px;" />
  </template>
  <template #suffix>
    <VxButton size="sm" variant="outline">Sign In</VxButton>
  </template>
  <template #item="{ item, active }">
    <button :class="{ 'my-custom-item': true, active }">
      {{ item.label }}
    </button>
  </template>
</VxMenu>

Router Integration ​

Use the to property on items for SPA navigation via vue-router.

vue
<VxMenu v-model="active" :items="[
  { key: 'home', label: 'Home', icon: 'home', to: '/' },
  { key: 'about', label: 'About', icon: 'user', to: '/about' },
  { key: 'docs', label: 'Docs', icon: 'file', to: { name: 'docs' } },
]" />

Context Menu ​

Right-click on "Home" or "Inbox" to see the context menu. Supports icons, destructive (red) items, and disabled items.

vue
<VxMenu v-model="active" :items="[
  {
    key: 'inbox',
    label: 'Inbox',
    icon: 'mail',
    contextMenu: [
      { label: 'Mark all read', icon: 'check', action: (item) => {} },
      { label: 'Settings', icon: 'settings', action: (item) => {} },
      { label: 'Delete all', icon: 'trash', destructive: true, action: (item) => {} },
    ],
  },
]" />

Responsive Drawer ​

Set responsive to automatically switch to a hamburger button on small screens. Drag the handle to resize and see the menu switch between desktop and mobile modes.

↔ drag to resize
vue
<VxMenu v-model="active" :items="items" responsive />
<!-- Custom breakpoint (default 768) -->
<VxMenu v-model="active" :items="items" responsive :breakpoint="640" />

Drag the bottom-right corner of the demo to resize. When the width drops below the breakpoint, the menu collapses into a hamburger icon. Click it to open a smooth left-side drawer.

Custom Drawer Title ​

Use drawer-title prop to change the header text, or use the drawer-header slot for full control.

vue
<!-- Simple title change -->
<VxMenu v-model="active" :items="items" responsive drawer-title="Navigation" />

<!-- Full custom header via slot -->
<VxMenu v-model="active" :items="items" responsive>
  <template #drawer-header>
    <img src="/logo.svg" style="height: 24px;" />
    <span style="font-weight: 600;">My App</span>
  </template>
</VxMenu>

Custom Drawer Width ​

Use drawer-width to change the drawer panel width. Accepts a number (px) or string.

vue
<VxMenu v-model="active" :items="items" responsive :drawer-width="220" />
<VxMenu v-model="active" :items="items" responsive :drawer-width="360" />
<VxMenu v-model="active" :items="items" responsive drawer-width="50%" />

Custom Burger & Close Icons ​

Use the burger-icon slot to replace the hamburger icon and drawer-close-icon to replace the close button icon.

vue
<VxMenu v-model="active" :items="items" responsive>
  <!-- Three-dot burger icon -->
  <template #burger-icon>
    <svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <circle cx="12" cy="12" r="1"/><circle cx="19" cy="12" r="1"/><circle cx="5" cy="12" r="1"/>
    </svg>
  </template>
  <!-- Arrow-left close icon -->
  <template #drawer-close-icon>
    <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
      <path d="m12 19-7-7 7-7"/><path d="M19 12H5"/>
    </svg>
  </template>
</VxMenu>

Dark Theme ​

vue
<VxMenu v-model="active" :items="items" theme="dark" />

Keyboard Navigation ​

The menu supports full keyboard navigation:

  • Arrow Left/Right — move focus between items
  • Arrow Down — open submenu
  • Enter / Space — select focused item
  • Escape — close submenu or context menu
  • Home / End — jump to first/last item

API ​

VxMenu Props ​

PropTypeDefaultDescription
itemsMenuItem[][]Menu items
v-modelstring''Active item key
theme'light' | 'dark''light'Color theme
borderedbooleantrueShow border and border-radius
radiusnumber | string12Menu border-radius (px)
item-radiusnumber | string8Item border-radius (px)
item-heightnumber | string38Item min-height (px)
overflowbooleanfalseCollapse excess items into "More" dropdown
indicatorbooleanfalseShow animated active indicator bar
stickybooleanfalseSticky position at top
loadingbooleanfalseShow skeleton placeholders
loading-countnumber4Number of skeleton items
responsivebooleanfalseAuto burger menu on small screens
breakpointnumber768Width threshold for burger mode
drawer-widthnumber | string280Drawer panel width
drawer-titlestring'Menu'Drawer header title text
root-classstring | string[] | object—Class on root
PropertyTypeRequiredDescription
keystringYesUnique identifier
labelstringYesDisplay text
iconstring | ComponentNoBuilt-in icon name or Vue component
disabledbooleanNoDisable this item
badgestring | numberNoBadge content
badgeType'default' | 'primary' | 'success' | 'warning' | 'danger'NoBadge color
dividerbooleanNoShow divider before
action(item) => voidNoClick callback
childrenMenuItem[]NoDropdown submenu items
tostring | objectNoVue Router navigation target
dotbooleanNoShow notification dot
dotColorstringNoDot color (default red)
contextMenuContextMenuItem[]NoRight-click menu items

Slots ​

SlotPropsDescription
prefix—Content before menu items
suffix—Content after menu items
item{ item, active }Custom item rendering
burger-icon—Custom burger button icon
drawer-header—Custom drawer header content
drawer-close-icon—Custom drawer close button icon
drawer-footer—Content below drawer items

Events ​

EventPayloadDescription
update:modelValue(key: string)Active item changed
select(key, item)Item selected
context-menu(item, event)Right-click on item