useMenu
Quickly define navigation menus for your website.
- More configurable options refer to MenuProps
Basic Usage
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{ index: '1', label: 'Processing Center' },
{ index: '2', label: 'Orders' },
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Top Bar
Set mode to horizontal for a top bar menu.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
mode: 'horizontal',
defaultActive: '1',
items: [
{ index: '1', label: 'Processing Center' },
{ index: '2', label: 'Orders' },
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Sub Menu
Use children to create a sub-menu with nested items.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{ index: '1', label: 'Processing Center' },
{
index: '2',
label: 'Workspace',
children: [
{ index: '2-1', label: 'item one' },
{ index: '2-2', label: 'item two' },
{ index: '2-3', label: 'item three' },
],
},
{ index: '3', label: 'Info', disabled: true },
{ index: '4', label: 'Orders' },
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Nested Sub Menu
Sub-menus can be nested to create multi-level menus.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{
index: '2',
label: 'Workspace',
children: [
{ index: '2-1', label: 'item one' },
{ index: '2-2', label: 'item two' },
{ index: '2-3', label: 'item three' },
{
index: '2-4',
label: 'item four',
children: [
{ index: '2-4-1', label: 'item one' },
{ index: '2-4-2', label: 'item two' },
{ index: '2-4-3', label: 'item three' },
],
},
],
},
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Select Event
The returned activeIndex ref tracks the selected menu item, and the onSelect callback fires on selection.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu, activeIndex] = useMenu({
defaultActive: '1',
items: [
{ index: '1', label: 'Processing Center' },
{ index: '2', label: 'Orders' },
],
onSelect: (index, indexPath, item) => {
console.log('selected:', index, indexPath, item)
},
})
</script>
<template>
<div>
<Menu />
<p>Active: {{ activeIndex }}</p>
</div>
</template>Open / Close Events
onOpen and onClose fire when sub-menus expand or collapse.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{
index: '1',
label: 'Workspace',
children: [
{ index: '1-1', label: 'item one' },
{ index: '1-2', label: 'item two' },
],
},
],
onOpen: (index, indexPath) => {
console.log('opened:', index, indexPath)
},
onClose: (index, indexPath) => {
console.log('closed:', index, indexPath)
},
})
</script>
<template>
<div>
<Menu />
</div>
</template>Custom render item content
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
import { h } from 'vue'
const [Menu] = useMenu({
items: [
{
index: '1',
label: 'Item 1',
render: (item) => {
return h('span', { class: 'item-content' }, `Custom: ${(item as { label: string }).label}`)
},
},
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Custom sub-menu title
Use renderTitle to customize the sub-menu title content.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
import { h } from 'vue'
const [Menu] = useMenu({
items: [
{
index: '1',
label: 'Workspace',
renderTitle: (item) => {
return h('span', { class: 'title-content' }, `Title: ${(item as { label: string }).label}`)
},
children: [
{ index: '1-1', label: 'item one' },
],
},
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Menu Item Group
Use groupTitle with children to render as a MenuItemGroup.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{
index: '1',
groupTitle: 'Group One',
children: [
{ index: '1-1', label: 'item one' },
{ index: '1-2', label: 'item two' },
],
},
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Collapse
Set collapse to true for a collapsed sidebar menu (vertical mode only).
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
collapse: true,
items: [
{ index: '1', label: 'Processing Center' },
{
index: '2',
label: 'Workspace',
children: [
{ index: '2-1', label: 'item one' },
{ index: '2-2', label: 'item two' },
],
},
],
})
</script>
<template>
<div>
<Menu />
</div>
</template>Custom Menu Content
Use the default slot to fully customize the menu content.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
import { h } from 'vue'
const [Menu] = useMenu({
items: [],
})
</script>
<template>
<div>
<Menu>
<div class="custom-menu">
Custom Menu Content
</div>
</Menu>
</div>
</template>Async Data
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
async function fetchMenuItems() {
const res = await fetch('/api/menu-items')
return res.json()
}
function formatData(data: any) {
return data.map((item: any) => ({
index: item.index,
label: item.label,
disabled: item.disabled,
children: item.children,
}))
}
const [Menu] = useMenu({
items: [],
service: fetchMenuItems,
formatData,
})
</script>
<template>
<div>
<Menu />
</div>
</template>Pass props to ElMenu
Pass additional props to the underlying ElMenu component.
vue
<script setup lang="ts">
import { useMenu } from '@vuecraft/components'
const [Menu] = useMenu({
items: [
{ index: '1', label: 'Processing Center' },
{ index: '2', label: 'Orders' },
],
mode: 'horizontal',
uniqueOpened: true,
menuTrigger: 'click',
popperEffect: 'light',
closeOnClickOutside: true,
showTimeout: 500,
hideTimeout: 400,
popperOffset: 12,
})
</script>
<template>
<div>
<Menu />
</div>
</template>Declaration Types
MenuColumn
typescript
interface MenuColumn {
// Index of the menu item, unique identification
index: string
// Label of the menu item
label?: string
// Whether the item is disabled
disabled?: boolean
// Vue Router object
route?: unknown
// Children of the sub-menu
children?: MenuColumn[]
// Render function of the item content
render?: (val: unknown) => VNode
// Render function of the title (for sub-menu)
renderTitle?: (val: unknown) => VNode
// Group title - if set with children, renders as MenuItemGroup
groupTitle?: string
// Sub-menu popper class
popperClass?: string
// Sub-menu popper style
popperStyle?: unknown
// Sub-menu show timeout
showTimeout?: number
// Sub-menu hide timeout
hideTimeout?: number
// Whether the sub-menu is teleported
teleported?: boolean
// Sub-menu popper offset
popperOffset?: number
// Icon when menu expanded and submenu closed
expandCloseIcon?: string | Component
// Icon when menu expanded and submenu opened
expandOpenIcon?: string | Component
// Icon when menu collapsed and submenu closed
collapseCloseIcon?: string | Component
// Icon when menu collapsed and submenu opened
collapseOpenIcon?: string | Component
}MenuOptions
typescript
interface MenuOptions<T> extends Partial<MenuProps> {
// Items of the menu
items?: MenuColumn[]
// Service
service?: RequestService<T>
// Service params
params?: unknown
// Format items data
formatData?: (data: T) => MenuColumn[]
// Default active index
defaultActive?: string
// Callback when a menu item is selected
onSelect?: (index: string, indexPath: string[], item: unknown, routerResult?: Promise<unknown>) => void
// Callback when a sub-menu opens
onOpen?: (index: string, indexPath: string[]) => void
// Callback when a sub-menu closes
onClose?: (index: string, indexPath: string[]) => void
}MenuReturnType
typescript
type MenuReturnType = [
// Menu component
Component,
// Active index ref, tracks the selected menu item
Ref<string>,
]