or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

component-api.mdfunctional-api.mdindex.mdmenu-bar.mdthemes.md
tile.json

tessl/npm-imengyu--vue3-context-menu

A comprehensive context menu component library for Vue 3 applications with themes, keyboard navigation, and programmatic control

Workspace
tessl
Visibility
Public
Created
Last updated
Describes
npmpkg:npm/@imengyu/vue3-context-menu@1.5.x

To install, run

npx @tessl/cli install tessl/npm-imengyu--vue3-context-menu@1.5.0

index.mddocs/

Vue3 Context Menu

Vue3 Context Menu is a comprehensive context menu component library for Vue 3 applications that enables developers to create customizable right-click menus with rich functionality. It offers both functional and component-based APIs for displaying context menus, supports nested submenus and separators, provides multiple built-in themes with both light and dark variants, and includes keyboard navigation support.

Package Information

  • Package Name: @imengyu/vue3-context-menu
  • Package Type: npm
  • Language: TypeScript
  • Installation: npm install @imengyu/vue3-context-menu

Core Imports

import ContextMenu from '@imengyu/vue3-context-menu';
import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css';

// For functional API
import ContextMenu from '@imengyu/vue3-context-menu';

// For component imports
import { 
  ContextMenu as ContextMenuComponent, 
  ContextMenuItem, 
  ContextMenuSeparator, 
  ContextMenuGroup,
  MenuBar 
} from '@imengyu/vue3-context-menu';

For CommonJS:

const ContextMenu = require('@imengyu/vue3-context-menu');
require('@imengyu/vue3-context-menu/lib/vue3-context-menu.css');

Basic Usage

Installation and Setup

import { createApp } from 'vue';
import ContextMenu from '@imengyu/vue3-context-menu';
import '@imengyu/vue3-context-menu/lib/vue3-context-menu.css';

const app = createApp(App);
app.use(ContextMenu);

Quick Example - Functional API

import ContextMenu from '@imengyu/vue3-context-menu';

function onContextMenu(e: MouseEvent) {
  e.preventDefault();
  
  ContextMenu.showContextMenu({
    x: e.x,
    y: e.y,
    items: [
      { 
        label: "Copy", 
        icon: "copy-icon",
        onClick: () => console.log("Copy clicked")
      },
      { 
        label: "Edit", 
        children: [
          { label: "Cut", onClick: () => console.log("Cut clicked") },
          { label: "Paste", onClick: () => console.log("Paste clicked") },
        ]
      },
      { divided: true, label: "Delete", onClick: () => console.log("Delete clicked") }
    ]
  });
}

Quick Example - Component API

<template>
  <div @contextmenu="onRightClick">
    <context-menu v-model:show="show" :options="menuOptions">
      <context-menu-item label="Copy" icon="copy-icon" @click="handleCopy" />
      <context-menu-separator />
      <context-menu-group label="Edit">
        <context-menu-item label="Cut" @click="handleCut" />
        <context-menu-item label="Paste" @click="handlePaste" />
      </context-menu-group>
    </context-menu>
  </div>
</template>

<script setup>
import { ref } from 'vue';

const show = ref(false);
const menuOptions = ref({
  x: 0,
  y: 0,
  zIndex: 1000
});

function onRightClick(e) {
  e.preventDefault();
  menuOptions.value.x = e.x;
  menuOptions.value.y = e.y;
  show.value = true;
}
</script>

Architecture

Vue3 Context Menu is built around several key components:

  • Functional API: Global methods for programmatic menu display (showContextMenu, closeContextMenu)
  • Component API: Vue components for declarative menu construction (ContextMenu, ContextMenuItem, etc.)
  • Theme System: Built-in themes (default, flat, win10, mac) with light/dark variants
  • Position System: Automatic position adjustment to prevent menu overflow
  • Keyboard Navigation: Full keyboard control support matching Windows menu behavior
  • Menu Bar: Traditional horizontal menu bar component for desktop-style applications

Capabilities

Functional API

Core programmatic interface for displaying context menus with full configuration control. Perfect for dynamic menus and event-driven scenarios.

interface ContextMenuGlobal {
  showContextMenu(options: MenuOptions, customSlots?: Record<string, Slot>): ContextMenuInstance;
  closeContextMenu(): void;
  isAnyContextMenuOpen(): boolean;
  transformMenuPosition(element: HTMLElement, x: number, y: number, container?: HTMLElement): { x: number, y: number };
}

interface MenuOptions {
  /** Menu items array */
  items?: MenuItem[];
  /** Menu display X position */
  x: number;
  /** Menu display Y position */
  y: number;
  /** X-coordinate offset of submenu and parent menu */
  xOffset?: number;
  /** Y-coordinate offset of submenu and parent menu */
  yOffset?: number;
  /** Theme name (default, flat, win10, mac, with optional 'dark' suffix) */
  theme?: string;
  /** Menu pop-up direction relative to coordinates */
  direction?: MenuPopDirection;
  /** Z-index for menu display */
  zIndex?: number;
  /** Menu zoom level */
  zoom?: number;
  /** Custom CSS class for menu */
  customClass?: string;
  /** Enable mouse scroll wheel in menu area */
  mouseScroll?: boolean;
  /** Provide space placeholder for up/down buttons */
  updownButtonSpaceholder?: boolean;
  /** Element class name to ignore clicks */
  ignoreClickClassName?: string;
  /** Close menu when clicking outside */
  clickCloseOnOutside?: boolean;
  /** Element class name that closes menu when clicked */
  clickCloseClassName?: string;
  /** Custom icon library font class name */
  iconFontClass?: string;
  /** Vue Transition props for menu show/hide */
  menuTransitionProps?: TransitionProps;
  /** Reserve fixed-width icon area for items without icon */
  preserveIconWidth?: boolean;
  /** Enable keyboard control */
  keyboardControl?: boolean;
  /** Maximum width of menu (pixels) */
  maxWidth?: number;
  /** Maximum height of menu (pixels) */
  maxHeight?: number;
  /** Minimum width of menu (pixels) */
  minWidth?: number;
  /** Close when user scrolls */
  closeWhenScroll?: boolean;
  /** Padding for submenu position adjustment */
  adjustPadding?: { x: number, y: number } | number;
  /** Automatically adjust position to prevent overflow */
  adjustPosition?: boolean;
  /** Container element for menu mounting */
  getContainer?: HTMLElement | (() => HTMLElement);
  /** Event when menu is closing */
  onClose?: (lastClickItem: MenuItem | undefined) => void;
  /** Event when clicking outside (when clickCloseOnOutside is false) */
  onClickOnOutside?: (e: MouseEvent) => void;
  /** Event for MenuBar left focus move */
  onKeyFocusMoveLeft?: () => void;
  /** Event for MenuBar right focus move */
  onKeyFocusMoveRight?: () => void;
}

Functional API

Component API

Vue components for declarative menu construction with full template integration. Ideal for static menus and component-based architectures.

// Main context menu component
declare component ContextMenu {
  props: {
    options: MenuOptions;
    show: boolean;
  };
  events: {
    'update:show': (show: boolean) => void;
    'close': () => void;
  };
}

// Menu item component
declare component ContextMenuItem {
  props: {
    label?: string;
    icon?: string;
    disabled?: boolean;
    hidden?: boolean;
    checked?: boolean;
    shortcut?: string;
  };
  events: {
    'click': (e: MouseEvent | KeyboardEvent) => void;
  };
}

// Menu separator component
declare component ContextMenuSeparator {
  // No props
}

// Menu group component for nested submenus
declare component ContextMenuGroup {
  props: {
    label: string;
  };
  // Contains slot for child menu items
}

Component API

Menu Bar

Traditional horizontal menu bar component for desktop-style applications with dropdown menus.

declare component MenuBar {
  props: {
    options: MenuBarOptions;
  };
}

interface MenuBarOptions extends Omit<MenuOptions, 'x'|'y'|'getContainer'> {
  mini?: boolean;
  barPopDirection?: MenuPopDirection;
}

Menu Bar

Themes and Styling

Built-in theme system with light and dark variants for different UI styles.

type ThemeNames = 
  | 'default' 
  | 'default dark'
  | 'flat'
  | 'flat dark'
  | 'win10'
  | 'win10 dark'
  | 'mac'
  | 'mac dark';

Themes and Styling

Types

Vue Types

// Vue framework types used throughout the API
interface VNode {
  // Vue virtual node for custom renders
}

interface ComputedRef<T> {
  // Vue computed reference
  readonly value: T;
}

interface Slot {
  // Vue slot function
  (...args: any[]): VNode[];
}

Core Types

type MenuPopDirection = 'br'|'b'|'bl'|'tr'|'t'|'tl'|'l'|'r';

interface MenuItem {
  /** Menu item label */
  label?: string | VNode | ((label: string) => VNode);
  /** Menu item icon */
  icon?: string | VNode | ((icon: string) => VNode);
  /** Custom icon font class name */
  iconFontClass?: string;
  /** Reserve fixed-width icon area */
  preserveIconWidth?: boolean;
  /** SVG symbol icon reference */
  svgIcon?: string;
  /** SVG element properties */
  svgProps?: SVGAttributes;
  /** Disable menu item */
  disabled?: boolean | ComputedRef<boolean>;
  /** Hide menu item */
  hidden?: boolean | ComputedRef<boolean>;
  /** Show check mark */
  checked?: boolean | ComputedRef<boolean>;
  /** Shortcut key display text */
  shortcut?: string;
  /** Submenu popup direction */
  direction?: MenuPopDirection;
  /** Adjust submenu position */
  adjustSubMenuPosition?: boolean;
  /** Allow click when has children */
  clickableWhenHasChildren?: boolean;
  /** Close menu on click */
  clickClose?: boolean;
  /** Separator display option */
  divided?: boolean | 'up' | 'down' | 'self';
  /** Custom CSS class */
  customClass?: string;
  /** Maximum height in pixels */
  maxHeight?: number;
  /** Maximum width in pixels */
  maxWidth?: number | string;
  /** Minimum width in pixels */
  minWidth?: number | string;
  /** Click event handler */
  onClick?: (e?: MouseEvent | KeyboardEvent) => void;
  /** Submenu close event */
  onSubMenuClose?: (itemInstance?: MenuItemContext) => void;
  /** Submenu open event */
  onSubMenuOpen?: (itemInstance?: MenuItemContext) => void;
  /** Custom render function */
  customRender?: VNode | ((item: MenuItem) => VNode);
  /** Child menu items */
  children?: MenuItem[];
}

interface ContextMenuInstance {
  /** Close the menu */
  closeMenu(fromItem?: MenuItem | undefined): void;
  /** Check if menu is closed */
  isClosed(): boolean;
  /** Get root menu instance */
  getMenuRef(): ContextSubMenuInstance | undefined;
  /** Get menu dimensions */
  getMenuDimensions(): { width: number, height: number };
}

interface ContextSubMenuInstance {
  /** Get submenu root element */
  getSubmenuRoot(): HTMLElement | undefined;
  /** Get menu container element */
  getMenu(): HTMLElement | undefined;
  /** Get child menu item by index */
  getChildItem(index: number): MenuItemContext | undefined;
  /** Get menu dimensions */
  getMenuDimensions(): { width: number, height: number };
  /** Get current scroll value */
  getScrollValue(): number;
  /** Set scroll value */
  setScrollValue(v: number): void;
  /** Get scroll height */
  getScrollHeight(): number;
  /** Force adjust position */
  adjustPosition(): void;
  /** Get maximum height */
  getMaxHeight(): number;
  /** Get current position */
  getPosition(): { x: number, y: number };
  /** Set position */
  setPosition(x: number, y: number): void;
}

interface MenuItemContext {
  /** Get submenu instance */
  getSubMenuInstance(): ContextSubMenuInstance | undefined;
  /** Show submenu */
  showSubMenu(): boolean;
  /** Hide submenu */
  hideSubMenu(): void;
  /** Get HTML element */
  getElement(): HTMLElement | undefined;
  /** Check if disabled or hidden */
  isDisabledOrHidden(): boolean;
  /** Focus item */
  focus(): void;
  /** Blur item */
  blur(): void;
  /** Click item */
  click(e: MouseEvent | KeyboardEvent): void;
}

interface SVGAttributes {
  [key: string]: any;
}

interface TransitionProps {
  name?: string;
  mode?: 'in-out' | 'out-in' | 'default';
  appear?: boolean;
  css?: boolean;
  type?: 'transition' | 'animation';
  duration?: number | { enter: number; leave: number };
  enterFromClass?: string;
  enterActiveClass?: string;
  enterToClass?: string;
  appearFromClass?: string;
  appearActiveClass?: string;
  appearToClass?: string;
  leaveFromClass?: string;
  leaveActiveClass?: string;
  leaveToClass?: string;
}