Components/ContextMenu

ContextMenu

General menu surface for right-click, controlled coordinates, Popover composition, and pre-close confirmation.

VerifiedSince 0.3.4

Usage

ContextMenu

Loading demo...

Anchor mode

The default is anchorMode="pointer", so the menu follows the mouse coordinates. Use anchorMode="reference" when the menu should behave more like a Popover/Dropdown and attach to the trigger area.

<!-- Follow mouse / provided coordinates. Good for standard context menus. -->
<TxContextMenu anchor-mode="pointer" />

<!-- Follow the trigger area. Good for dropdown-like menus. -->
<TxContextMenu anchor-mode="reference" />

TxContextMenuSubmenu nests another panel inside the menu, at any depth. Hovering the trigger row expands it; pointer travel between the parent and child panels never closes the chain by mistake, nor does a diagonal path across sibling rows expand them, and selecting an item inside the child closes the whole chain following the root menu's closeOnSelect.

ContextMenuSubmenu

Loading demo...

Best Practices

  • Use TxContextMenu when you need trigger handling, coordinates, viewport collision handling, and open state in one component.
  • Use TxContextMenuPanel inside TxPopover for secondary menus or dropdown-like surfaces that should reuse ContextMenu item behavior without another trigger layer.
  • Prefer trigger="manual" with explicit x / y for editor shortcuts, command surfaces, canvas nodes, and any trigger that is not a native right-click or simple click.
  • Keep anchorMode="pointer" for real context menus; switch to reference only when the menu should align to the whole trigger element.
  • For teleported submenus, set outsideGuard on the child TxContextMenuPanel; otherwise the parent outside-click logic can treat submenu clicks as external.
  • Use closeOnSelect=false only for parent submenu rows or multi-step actions. Normal menu commands should close after selection.
  • The default activationFeedback=true clears the highlight for 90 ms, confirms with the existing active state for 90 ms, then emits select and closes. Reduced motion skips it automatically; disable it at the root, panel, or item when the host already provides stronger immediate feedback.
  • Keep destructive actions visually explicit with danger; use color only for semantic product colors that are already part of the design system.

API Reference

TxContextMenu Props

PropTypeDefaultDescription
modelValueboolean | undefinedundefinedControlled open state; leave undefined for internal uncontrolled state.
xnumber0Controlled/manual anchor X coordinate.
ynumber0Controlled/manual anchor Y coordinate.
widthnumber220Menu width in pixels; 0 keeps automatic width.
minWidthnumber0Minimum width.
maxWidthnumber360Maximum width; 0 means unlimited.
maxHeightnumber420Maximum height; also constrained by available viewport height.
unlimitedHeightbooleanfalseDisables height limiting.
disabledbooleanfalseDisables triggers and opening.
eagerbooleanfalseMounts menu content before first open.
trigger'contextmenu' | 'click' | 'both' | 'manual''contextmenu'Trigger mode. manual opens only through external state/coordinates.
anchorMode'pointer' | 'reference''pointer'Anchor mode. pointer follows the mouse / provided coordinates; reference follows the trigger area.
preventDefaultbooleantruePrevents the browser native context menu on right-click.
placementBaseAnchorPlacement'bottom-start'Initial placement relative to the coordinate point. Supports top/bottom/left/right and start/end variants.
offsetnumber2Distance from the coordinate point.
closeOnEscbooleantrueCloses the menu on Escape.
closeOnClickOutsidebooleantrueCloses the menu on pointer events outside the menu.
closeOnTriggerPointerDownbooleantrueCloses when users click the trigger area after the menu is open; automatically ignored for click / both trigger modes to avoid closing immediately after opening.
closeOnAnyPointerDownbooleanfalseCloses on any non-menu pointer down, including the trigger area and the rest of the page.
closeOnSelectbooleantrueCloses the menu after an item is selected.
activationFeedbackbooleantrueRuns a 90 ms clear + 90 ms confirmation before select and close for closing commands; reduced motion skips it.
showArrowbooleanfalseShows an arrow pointing to the coordinate anchor.
arrowSizenumber10Arrow size.
animationBaseAnchorAnimationOptions{}Enter/leave animation. Supports transfer, boom, opacity, and none.
keepAliveContentbooleantruePreserves content state after close.
panelVariant'solid' | 'dashed' | 'plain''solid'Panel border style.
panelBackground'pure' | 'mask' | 'blur' | 'glass' | 'refraction''refraction'Panel background effect.
panelShadow'none' | 'soft' | 'medium''medium'Panel shadow.
panelRadiusnumber14Panel radius.
panelPaddingnumber6Panel padding.
panelCardBaseAnchorPanelCardProps-Advanced visual props forwarded to the internal TxCard.

TxContextMenu Events

EventParamsDescription
update:modelValuebooleanEmitted when open state changes.
open{ x: number; y: number }Emitted when the menu opens with the active anchor coordinates.
close-Emitted when the menu closes.

TxContextMenu Exposes

NameTypeDescription
openAt(target?: { x: number; y: number } | MouseEvent | PointerEvent) => voidOpens the menu at a point or event coordinate.
openFromEvent(event: MouseEvent | PointerEvent) => voidOpens from a mouse/pointer event.
close() => voidCloses the menu.
updatePosition() => voidManually refreshes Floating UI placement.

TxContextMenuPanel Props

PropTypeDefaultDescription
widthnumber | string-Panel width.
minWidthnumber | string-Minimum width.
maxWidthnumber | string-Maximum width.
maxHeightnumber | string-Maximum height.
closeOnSelectbooleantrueWhether child items close the panel after selection.
activationFeedbackbooleantruePre-close confirmation inherited by child items; individual items may override it.
close() => void-Close callback injected into child items.
densebooleanfalseUses tighter item spacing.
outsideGuardbooleanfalseMarks the panel as a protected ContextMenu layer for teleported submenus.
role'menu' | 'listbox' | 'none''menu'Panel ARIA role, which also drives keyboard navigation: menu/listbox enable arrow keys, Home/End, and focusFirstItem, with child items set to role="menuitem" (menu) or role="option" (listbox) accordingly; none opts out of keyboard navigation (no focusable items, so focusFirstItem is a no-op).
ariaLabelstring-ARIA label.

TxContextMenuPanel Exposes

NameTypeDescription
focusFirstItem() => voidMoves keyboard focus to the first enabled item in the panel. Only needed when you embed a standalone TxContextMenuPanel inside TxPopover / a custom overlay: call it after the panel opens to send focus into the menu for keyboard navigation. TxContextMenu calls it automatically on open; a bare panel does not. When role is none the panel has no navigable items, so the call is a no-op.

TxContextMenuItem Props

PropTypeDefaultDescription
disabledbooleanfalseDisables selection and clickability.
dangerbooleanfalseApplies danger styling to the label.
colorstring-Custom label color. CSS variables are supported.
shortcutstring-Shortcut hint rendered on the right.
submenubooleanfalseShows a submenu arrow.
closeOnSelectboolean-Overrides parent closeOnSelect.
activationFeedbackboolean-Overrides inherited confirmation feedback; unset follows the nearest TxContextMenuPanel.

TxContextMenuItem Events

EventParamsDescription
select-Emitted when an enabled item is selected. Closing items with feedback enabled emit after the 180 ms confirmation; bypass paths emit immediately.

TxContextMenuSubmenu Props

PropTypeDefaultDescription
disabledbooleanfalseDisables the trigger row; the child panel no longer opens.
placementBaseAnchorPlacement'right-start'Positions the child panel relative to the trigger row.
offsetnumber4Distance in pixels between the trigger row and the child panel.
widthnumber0Fixed child panel width; 0 sizes to content bounded by minWidth.
minWidthnumber160Minimum child panel width in pixels.
maxHeightnumber420Maximum child panel height in pixels.
unlimitedHeightbooleanfalseDisables the child panel max-height constraint.
animationBaseAnchorAnimationOptions{}Anchor animation config for the child panel.
panelCardBaseAnchorPanelCardProps-Low-level card props forwarded to the child panel.
panelVariant'solid' | 'dashed' | 'plain''solid'Visual border variant of the child panel.
panelBackground'pure' | 'mask' | 'blur' | 'glass' | 'refraction''refraction'Background treatment of the child panel.
panelShadow'none' | 'soft' | 'medium''medium'Shadow strength of the child panel.
panelRadiusnumber14Child panel corner radius in pixels.
panelPaddingnumber6Child panel padding in pixels.

TxContextMenuDivider Props

PropTypeDefaultDescription
dashedbooleanfalseUses a dashed separator.
insetbooleanfalseAdds left inset to align with icon/nested content.

Slots

TxContextMenu

SlotPropsDescription
trigger-Custom trigger element. The default slot is used as fallback trigger content.
default-Fallback trigger content when trigger is not provided.
menu-Menu content rendered inside the internal TxContextMenuPanel.

TxContextMenuPanel

SlotPropsDescription
default-Menu items, dividers, or nested overlay content.

TxContextMenuItem

SlotPropsDescription
default-Main item label.
avatar-Leading icon/avatar content forwarded to TxCardItem.
description-Secondary description text forwarded to TxCardItem.
right-Replaces the generated shortcut/submenu area.

TxContextMenuSubmenu

SlotPropsDescription
default-Main trigger row label.
right-Trailing metadata on the trigger row, rendered before the submenu chevron.
menu-Child panel content, usually TxContextMenuItem rows or nested TxContextMenuSubmenu.

TxContextMenuDivider does not expose slots.

Overview

  • Placement: TxContextMenu positions itself through TxBaseAnchor with Floating UI flip + shift + size, flipping/shifting near viewport edges and constraining max height to the available viewport.
  • Anchor: anchorMode="pointer" (default) follows the mouse / provided coordinates and updates the virtual anchor to the latest position on repeated right-clicks; anchorMode="reference" follows the trigger area, more like a Dropdown.
  • Trigger: trigger supports contextmenu / click / both / manual; manual disables internal event handling and opens only through v-model + x/y, for button clicks, editor shortcuts, and canvas node menus.
  • Close: Escape, outside click, and item selection close by default; closeOnSelect=false parent-submenu or multi-step rows select immediately without blinking.
  • Confirmation: activationFeedback is enabled by default. The item clears its current hover/focus highlight, reuses TxCardItem's active style to confirm, then runs the business action and closes. Root configuration reaches nested submenus, panels/items may override it, and prefers-reduced-motion: reduce adds no delay.
  • Submenus: prefer TxContextMenuSubmenu — it ships hover expansion, the safe triangle (sibling submenu rows crossed on a diagonal path to the child panel do not expand; resting on one for about 100ms switches to it), keyboard traversal, outside-click exemption, and whole-chain close; TxContextMenuPanel can still be embedded manually in TxPopover / a custom overlay, in which case a teleported child panel must set outsideGuard, otherwise the parent treats the submenu click as an outside click and closes.
  • Animation: handled directly by BaseAnchor — transfer / boom / opacity / none.

Technologies

  • Source: packages/tuffex/packages/components/src/context-menu/src/TxContextMenu.vue confirms controlled/uncontrolled open state, pointer/reference virtual anchors, trigger modes, outside-click handling, BaseAnchor forwarding, and root activationFeedback.
  • Source: packages/tuffex/packages/components/src/context-menu/src/TxContextMenuPanel.vue confirms panel layout, closeOnSelect / activationFeedback / close injection, dense, outsideGuard, role, and ariaLabel behavior.
  • Source: packages/tuffex/packages/components/src/context-menu/src/TxContextMenuItem.vue confirms disabled, danger, custom color, shortcut, submenu, per-item closeOnSelect / activationFeedback, item slots, and pre-close confirmation.
  • Source: packages/tuffex/packages/components/src/context-menu/src/TxContextMenuSubmenu.vue confirms hover expansion, keyboard traversal, root close/confirmation context passthrough, and automatic outsideGuard; its closeOnSelect=false trigger never runs feedback.
  • Shared behavior: packages/tuffex/packages/utils/menu-activation-feedback.ts owns the 90 ms clear / 90 ms confirm state machine, reduced-motion bypass, duplicate suppression, and unmount cleanup.
  • Type contracts: packages/tuffex/packages/components/src/context-menu/src/types.ts exports trigger, anchor, panel visual enums, confirmation props, and open-target shapes.
  • Verified coverage: Coverage: packages/tuffex/packages/components/src/context-menu/__tests__/context-menu.test.ts covers controlled width, right-click/coordinate opening, Escape and pointerdown close guards, pointer/reference anchors, pointer and keyboard confirmation timing, duplicate suppression, root/panel/item opt-out, reduced motion, unmount cleanup, closeOnSelect=false, nested root close, and shortcut/color/submenu rendering.
查看源码
packages/tuffex/packages/components/src/context-menu/index.ts