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
<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.
<VxMenu v-model="active" :items="items" :bordered="false" />Custom Sizing
Customize the menu border-radius, item border-radius, and item height.
<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
<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' },
]" />Dropdown Submenus
Hover over a parent item to reveal its dropdown children. The parent highlights when a child is active.
<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.
<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.
<VxMenu v-model="active" :items="items" indicator />Sticky
Set sticky to pin the menu at the top of the scroll container.
<VxMenu v-model="active" :items="items" sticky />Overflow
When items don't fit, excess items collapse into a "More" dropdown.
<VxMenu v-model="active" :items="items" overflow />Loading
Show skeleton placeholders while data is being fetched.
<VxMenu loading :loading-count="5" />Slots
Use prefix and suffix slots to add content around items. Use the item slot to customize item rendering.
<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.
<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.
<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.
<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.
<!-- 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.
<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.
<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
<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
| Prop | Type | Default | Description |
|---|---|---|---|
items | MenuItem[] | [] | Menu items |
v-model | string | '' | Active item key |
theme | 'light' | 'dark' | 'light' | Color theme |
bordered | boolean | true | Show border and border-radius |
radius | number | string | 12 | Menu border-radius (px) |
item-radius | number | string | 8 | Item border-radius (px) |
item-height | number | string | 38 | Item min-height (px) |
overflow | boolean | false | Collapse excess items into "More" dropdown |
indicator | boolean | false | Show animated active indicator bar |
sticky | boolean | false | Sticky position at top |
loading | boolean | false | Show skeleton placeholders |
loading-count | number | 4 | Number of skeleton items |
responsive | boolean | false | Auto burger menu on small screens |
breakpoint | number | 768 | Width threshold for burger mode |
drawer-width | number | string | 280 | Drawer panel width |
drawer-title | string | 'Menu' | Drawer header title text |
root-class | string | string[] | object | — | Class on root |
MenuItem
| Property | Type | Required | Description |
|---|---|---|---|
key | string | Yes | Unique identifier |
label | string | Yes | Display text |
icon | string | Component | No | Built-in icon name or Vue component |
disabled | boolean | No | Disable this item |
badge | string | number | No | Badge content |
badgeType | 'default' | 'primary' | 'success' | 'warning' | 'danger' | No | Badge color |
divider | boolean | No | Show divider before |
action | (item) => void | No | Click callback |
children | MenuItem[] | No | Dropdown submenu items |
to | string | object | No | Vue Router navigation target |
dot | boolean | No | Show notification dot |
dotColor | string | No | Dot color (default red) |
contextMenu | ContextMenuItem[] | No | Right-click menu items |
Slots
| Slot | Props | Description |
|---|---|---|
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
| Event | Payload | Description |
|---|---|---|
update:modelValue | (key: string) | Active item changed |
select | (key, item) | Item selected |
context-menu | (item, event) | Right-click on item |