Skip to content

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.

vue
<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.

vue
<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).
vue
<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>

The menu data (menus) supports rich configurations, including icons, shortcut key descriptions, dividers, and badges (Tag/Badge).

vue
<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.

vue
<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

PropertyDescriptionTypeDefault
menusList of menu item data (see table below)Array[]
triggerTrigger method: 'click', 'hover', 'contextmenu'String'contextmenu'
placementPopup position: top/bottom/left/right and their start/end combinationsString'bottom-start'
offsetPopup offset distance (px)Number8
maxWidthMaximum menu width (px)Number200
zIndexMenu z-index levelNumber2000
disabledWhether the menu is disabledBooleanfalse
menuClickCallback function for menu item clicksFunctionnull
appendToDOM node selector for mounting (Component mode only)String
classNameCustom class nameString''

Structure of objects in the menus array:

PropertyDescriptionType
labelText displayed for the menu itemString
valueUnique identifier for the item (returned in click callback)String / Number
iconIcon class name (e.g., tui-icon ti-copy)String
descriptionAuxiliary text on the right (often used for shortcut hints)String
dividerWhether to display a divider line below this itemBoolean
tagContentBadge content (numeric or text)String / Number
tagTypeBadge type (color): primary, success, warning, dangerString

Events

Event NameDescriptionCallback Parameters
menuClickTriggered when a menu item is clicked(params: Object, item: Object, index: Number)

Expose

NameDescriptionType
showManually show the menu() => void
hideManually hide the menu() => void
toggleToggle 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, the escCounter changes, 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 the clickCounter and passes the current clickTarget (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 offset property.

Simply specify the desired orientation through the component's placement attribute, and the underlying engine will handle the rest of the complex calculations.

Released under the MIT License.