Element Plus Menu Component
Menu that provides navigation for your website.
When to Invoke
Invoke this skill when:
- User needs to create a navigation menu
- User wants horizontal or vertical menu
- User needs collapsible sidebar menu
- User wants to integrate with Vue Router
- User asks about submenu or menu groups
Features
- Multiple Modes: Horizontal (top bar) and vertical (sidebar)
- Collapsible: Vertical menu can be collapsed
- Vue Router Integration: Automatic route navigation
- Submenus: Multi-level nested menus
- Menu Groups: Group related menu items
- Customizable: Colors, icons, and themes
- Accessibility: Keyboard navigation support
API Reference
Menu Attributes
| Name |
Description |
Type |
Default |
| mode |
menu display mode |
'horizontal' | 'vertical' |
vertical |
| collapse |
whether the menu is collapsed (only vertical mode) |
boolean |
false |
| ellipsis |
whether the menu is ellipsis (only horizontal mode) |
boolean |
true |
| ellipsis-icon |
custom ellipsis icon (only horizontal mode) |
string | Component |
— |
| popper-offset |
offset of the popper |
number |
6 |
| default-active |
index of active menu on page load |
string |
'' |
| default-openeds |
array of expanded sub-menus indexes |
string[] |
[] |
| unique-opened |
whether only one sub-menu can be active |
boolean |
false |
| menu-trigger |
how sub-menus are triggered (horizontal mode) |
'hover' | 'click' |
hover |
| router |
whether vue-router mode is activated |
boolean |
false |
| collapse-transition |
whether to enable collapse transition |
boolean |
true |
| popper-effect |
Tooltip theme when collapsed |
'dark' | 'light' |
dark |
| close-on-click-outside |
whether menu collapses when clicking outside |
boolean |
false |
| popper-class |
custom class for popup menus |
string |
— |
| popper-style |
custom style for popup menus |
string | object |
— |
| show-timeout |
timeout before showing menu |
number |
300 |
| hide-timeout |
timeout before hiding menu |
number |
300 |
Menu Events
| Name |
Description |
Type |
| select |
callback when menu is activated |
(index, indexPath, item, routerResult) => void |
| open |
callback when sub-menu expands |
(index, indexPath) => void |
| close |
callback when sub-menu collapses |
(index, indexPath) => void |
Menu Slots
| Name |
Description |
Subtags |
| default |
customize default content |
SubMenu / MenuItem / MenuItemGroup |
Menu Exposes
| Name |
Description |
Type |
| open |
open a specific sub-menu |
(index: string) => void |
| close |
close a specific sub-menu |
(index: string) => void |
| handleResize |
manually trigger menu width recalculation |
() => void |
| updateActiveIndex |
set index of active menu |
(index: string) => void |
SubMenu Attributes
| Name |
Description |
Type |
Default |
| index |
unique identification (required) |
string |
— |
| popper-class |
custom class for popup menu |
string |
— |
| popper-style |
custom style for popup menu |
string | object |
— |
| show-timeout |
timeout before showing |
number |
— |
| hide-timeout |
timeout before hiding |
number |
— |
| disabled |
whether disabled |
boolean |
false |
| teleported |
whether popup is teleported |
boolean |
undefined |
| popper-offset |
offset of the popper |
number |
— |
| expand-close-icon |
icon when expanded and submenu closed |
string | Component |
— |
| expand-open-icon |
icon when expanded and submenu open |
string | Component |
— |
| collapse-close-icon |
icon when collapsed and submenu closed |
string | Component |
— |
| collapse-open-icon |
icon when collapsed and submenu open |
string | Component |
— |
SubMenu Slots
| Name |
Description |
Subtags |
| default |
customize default content |
SubMenu / MenuItem / MenuItemGroup |
| title |
customize title content |
— |
MenuItem Attributes
| Name |
Description |
Type |
Default |
| index |
unique identification (required) |
string |
— |
| route |
Vue Router route parameters |
string | object |
— |
| disabled |
whether disabled |
boolean |
false |
MenuItem Events
| Name |
Description |
Type |
| click |
callback when menu-item is clicked |
(item) => void |
MenuItem Slots
| Name |
Description |
| default |
customize default content |
| title |
customize title content |
MenuItemGroup Attributes
| Name |
Description |
Type |
Default |
| title |
group title |
string |
— |
MenuItemGroup Slots
| Name |
Description |
Subtags |
| default |
customize default content |
MenuItem |
| title |
customize group title |
— |
Usage Examples
Top Bar (Horizontal)
<template>
<el-menu
:default-active="activeIndex"
mode="horizontal"
@select="handleSelect"
>
<el-menu-item index="1">Processing Center</el-menu-item>
<el-sub-menu index="2">
<template #title>Workspace</template>
<el-menu-item index="2-1">Item One</el-menu-item>
<el-menu-item index="2-2">Item Two</el-menu-item>
<el-menu-item index="2-3">Item Three</el-menu-item>
</el-sub-menu>
<el-menu-item index="3" disabled>Info</el-menu-item>
<el-menu-item index="4">Orders</el-menu-item>
</el-menu>
</template>
<script setup>
import { ref } from 'vue'
const activeIndex = ref('1')
const handleSelect = (key, keyPath) => {
console.log(key, keyPath)
}
</script>
Left And Right Alignment
<template>
<el-menu mode="horizontal">
<el-menu-item index="1">Left Item</el-menu-item>
<el-menu-item index="2">Left Item</el-menu-item>
<div style="flex-grow: 1" />
<el-menu-item index="3">Right Item</el-menu-item>
<el-menu-item index="4">Right Item</el-menu-item>
</el-menu>
</template>
Sidebar (Vertical)
<template>
<el-menu
:default-active="activeIndex"
class="el-menu-vertical"
>
<el-menu-item index="1">
<el-icon><location /></el-icon>
<span>Navigator One</span>
</el-menu-item>
<el-menu-item index="2">
<el-icon><document /></el-icon>
<span>Navigator Two</span>
</el-menu-item>
<el-menu-item index="3">
<el-icon><setting /></el-icon>
<span>Navigator Three</span>
</el-menu-item>
</el-menu>
</template>
<script setup>
import { ref } from 'vue'
import { Location, Document, Setting } from '@element-plus/icons-vue'
const activeIndex = ref('1')
</script>
<style>
.el-menu-vertical {
width: 200px;
min-height: 400px;
}
</style>
Collapsible Sidebar
<template>
<el-radio-group v-model="isCollapse" style="margin-bottom: 20px">
<el-radio-button :value="false">Expand</el-radio-button>
<el-radio-button :value="true">Collapse</el-radio-button>
</el-radio-group>
<el-menu
:default-active="activeIndex"
:collapse="isCollapse"
class="el-menu-vertical"
>
<el-menu-item index="1">
<el-icon><HomeFilled /></el-icon>
<template #title>Home</template>
</el-menu-item>
<el-sub-menu index="2">
<template #title>
<el-icon><Document /></el-icon>
<span>Documents</span>
</template>
<el-menu-item index="2-1">Recent</el-menu-item>
<el-menu-item index="2-2">Starred</el-menu-item>
</el-sub-menu>
<el-menu-item index="3">
<el-icon><Setting /></el-icon>
<template #title>Settings</template>
</el-menu-item>
</el-menu>
</template>
<script setup>
import { ref } from 'vue'
import { HomeFilled, Document, Setting } from '@element-plus/icons-vue'
const isCollapse = ref(false)
const activeIndex = ref('1')
</script>
<style>
.el-menu-vertical:not(.el-menu--collapse) {
width: 200px;
}
</style>
With Vue Router
<template>
<el-menu
:default-active="$route.path"
router
>
<el-menu-item index="/dashboard">
<el-icon><HomeFilled /></el-icon>
<span>Dashboard</span>
</el-menu-item>
<el-menu-item index="/users">
<el-icon><User /></el-icon>
<span>Users</span>
</el-menu-item>
<el-menu-item index="/settings">
<el-icon><Setting /></el-icon>
<span>Settings</span>
</el-menu-item>
</el-menu>
</template>
Menu Groups
<template>
<el-menu :default-active="activeIndex">
<el-menu-item-group title="Group One">
<el-menu-item index="1-1">Option 1</el-menu-item>
<el-menu-item index="1-2">Option 2</el-menu-item>
</el-menu-item-group>
<el-menu-item-group title="Group Two">
<el-menu-item index="2-1">Option 3</el-menu-item>
<el-menu-item index="2-2">Option 4</el-menu-item>
</el-menu-item-group>
</el-menu>
</template>
Common Issues
1. Menu Not Updating Active State
Use updateActiveIndex method:
<script setup>
const menuRef = ref()
const updateActive = (index) => {
menuRef.value?.updateActiveIndex(index)
}
</script>
2. Router Navigation Not Working
Ensure router prop is set and index matches route path:
<el-menu router>
<el-menu-item index="/dashboard">Dashboard</el-menu-item>
</el-menu>
3. Custom Height in Horizontal Mode
Override CSS variable:
.el-menu--horizontal {
--el-menu-horizontal-height: 80px;
}
Best Practices
- Use router mode: Integrate with Vue Router for SPA navigation
- Consistent icons: Use icons consistently across menu items
- Group related items: Use MenuItemGroup for organization
- Collapse for mobile: Use collapse mode for responsive design
- Unique indexes: Ensure each menu item has a unique index