Menu
The Menu component is used to display a list of operation commands or options. It supports multiple trigger methods such as clicking, hovering, and right-clicking, and provides a flexible positioning strategy.
Component Usage
Wrap the trigger element (such as a button) with the <TuiMenu> component. By default, it acts as a context menu (trigger="contextmenu"), but in standard interactions, it is commonly set to click or hover.
<script setup>
import { reactive } from 'vue'
const menuItems = [
{ label: 'Copy', value: 'copy', icon: 'tui-icon ti-copy' },
{ label: 'Paste', value: 'paste', icon: 'tui-icon ti-paste' },
{ label: 'Delete', value: 'delete', icon: 'tui-icon ti-trash', divider: true },
{ label: 'Properties', value: 'prop', icon: 'tui-icon ti-info-circle' }
]
const handleMenuClick = (params) => {
console.log('Clicked:', params)
}
</script>
<template>
<TuiMenu
trigger="click"
placement="bottom-start"
:menus="menuItems"
@menuClick="handleMenuClick"
>
<TuiButton>Click to open menu</TuiButton>
</TuiMenu>
</template>Directive Usage
TechUI provides the v-tui-menu directive, which is a more lightweight and recommended approach. It can be mounted directly onto any DOM element without altering the DOM structure.
<template>
<TuiButton
v-tui-menu="{
trigger: 'hover',
placement: 'top',
menus: menuItems,
menuClick: handleMenuClick
}"
>
Hover to view menu
</TuiButton>
</template>Trigger Methods
Control how the menu is activated using the trigger attribute:
- click: Triggered by a left-click (dropdown menu).
- hover: Triggered by mouse hover (sub-menus or tooltips).
- contextmenu: Triggered by a right-click (context menu).
<template>
<div class="demo-box">
<TuiButton v-tui-menu="{ trigger: 'click', menus: [...] }">
Click Trigger
</TuiButton>
<TuiButton v-tui-menu="{ trigger: 'hover', menus: [...] }">
Hover Trigger
</TuiButton>
<div
class="context-area"
v-tui-menu="{ trigger: 'contextmenu', menus: [...] }"
>
Right-click in this area
</div>
</div>
</template>Menu Item Configuration
The menu data (menus) supports rich configurations, including icons, shortcut key descriptions, dividers, and badges (Tag/Badge).
<script setup>
const richMenus = [
{
label: 'New File',
value: 'new',
icon: 'tui-icon ti-file',
description: 'Ctrl+N' // Shortcut hint on the right
},
{
label: 'Save',
value: 'save',
icon: 'tui-icon ti-save',
divider: true // Display a divider line
},
{
label: 'Notifications',
value: 'msg',
icon: 'tui-icon ti-bell',
tagContent: 8, // Display a numeric badge
tagType: 'success' // Badge color type
},
{
label: 'Urgent Task',
value: 'urgent',
tagContent: 'Urgent', // Display a text badge
tagType: 'danger'
}
]
</script>
<template>
<TuiMenu trigger="click" :menus="richMenus">
<TuiButton>Open Rich Menu</TuiButton>
</TuiMenu>
</template>Orientation and Positioning
Supports precise positioning across 12 orientations to adapt to complex page layouts:
top, top-start, top-end, bottom, bottom-start, bottom-end, left, left-start, left-end, right, right-start, right-end.
<template>
<div class="row">
<TuiButton v-tui-menu="{ placement: 'top-start', menus: [...] }">Top Start</TuiButton>
<TuiButton v-tui-menu="{ placement: 'top', menus: [...] }">Top</TuiButton>
<TuiButton v-tui-menu="{ placement: 'top-end', menus: [...] }">Top End</TuiButton>
</div>
<div class="row">
<TuiButton v-tui-menu="{ placement: 'right', menus: [...] }">Right</TuiButton>
</div>
</template>API Reference
Menu Props
| Property | Description | Type | Default |
|---|---|---|---|
| menus | List of menu item data (see table below) | Array | [] |
| trigger | Trigger method: 'click', 'hover', 'contextmenu' | String | 'contextmenu' |
| placement | Popup position: top/bottom/left/right and their start/end combinations | String | 'bottom-start' |
| offset | Popup offset distance (px) | Number | 8 |
| maxWidth | Maximum menu width (px) | Number | 200 |
| zIndex | Menu z-index level | Number | 2000 |
| disabled | Whether the menu is disabled | Boolean | false |
| menuClick | Callback function for menu item clicks | Function | null |
| appendTo | DOM node selector for mounting (Component mode only) | String | — |
| className | Custom class name | String | '' |
Menu Item Options
Structure of objects in the menus array:
| Property | Description | Type |
|---|---|---|
| label | Text displayed for the menu item | String |
| value | Unique identifier for the item (returned in click callback) | String / Number |
| icon | Icon class name (e.g., tui-icon ti-copy) | String |
| description | Auxiliary text on the right (often used for shortcut hints) | String |
| divider | Whether to display a divider line below this item | Boolean |
| tagContent | Badge content (numeric or text) | String / Number |
| tagType | Badge type (color): primary, success, warning, danger | String |
Events
| Event Name | Description | Callback Parameters |
|---|---|---|
| menuClick | Triggered when a menu item is clicked | (params: Object, item: Object, index: Number) |
Expose
| Name | Description | Type |
|---|---|---|
| show | Manually show the menu | () => void |
| hide | Manually hide the menu | () => void |
| toggle | Toggle the visibility state | () => void |
Global Interaction Monitoring
To provide a precise closing experience, the TuiMenu component is deeply integrated with TechUI's global service (TuiService). It monitors two core counters to achieve intelligent interaction:
- ESC Response (
escCounter): The component monitors the global ESC key. When a user presses Esc, theescCounterchanges, and all active menus will close automatically. - Intelligent Click Detection (
clickCounter): The component listens for global click events. Every time a click occurs, the global service updates theclickCounterand passes the currentclickTarget(the clicked DOM element). The component uses this parameter to perform a "Contains Check": the hide logic is only triggered if the click target is neither inside the menu panel nor inside the trigger element. This mechanism ensures that "Click Outside" logic remains accurate even in complex nested DOM structures.
Positioning Dependency
The anchor positioning calculations for TechUI's popovers and overlay components rely entirely on the industry-standard Floating UI library.
This means the component automatically handles the following scenarios without requiring complex geometric calculations:
- Collision Detection (Flip): If there is insufficient space in the preset position (e.g., at the screen edge), it automatically flips to the opposite side.
- Viewport Correction (Shift): Ensures the popover remains within the visible viewport and is not truncated.
- Precise Offset: Achieves pixel-level positioning through the
offsetproperty.
Simply specify the desired orientation through the component's placement attribute, and the underlying engine will handle the rest of the complex calculations.