Context Menu
Props
| Name | Type | Default | Description |
|---|---|---|---|
items | ContextMenuOption[] | - | The data-driven menu content. An entry is an action row, a divider { type: 'divider' }, or a section { type: 'section', title, items }; a row that carries items becomes a submenu. Omit it and use the content slot. |
menuWidth | number | string | undefined | Width of the menu panel. Numbers are interpreted as pixels. Without it the panel is at least 160px wide and sizes to its rows; either way it never overflows the viewport. |
size | 'sm' | 'md' | 'lg' | 'md' | Row density. It changes the rows' block padding only; type, radius, and panel styling stay the same in every size. |
label | string | 'Context menu' | Accessible name of the menu, announced through the panel's aria-label when it opens. |
isDisabled | boolean | false | Leaves the right-click to the browser and never opens the menu; an open menu is closed. The native context menu still appears. |
triggerAs | 'div' | 'span' | 'div' | Whether the trigger renders as a block div or an inline span for a word inside running prose. |
v-model:isOpen | boolean | - | Controlled open state. While bound the menu renders exactly this value; leave it unbound to let the menu own its state, opened by a right-click, the context-menu key, or a long press. |
Slots
| Name | Description |
|---|---|
default | The trigger area: right-clicking this content opens the menu. |
content | The menu content in compound mode, composed from ContextMenuItem, ContextMenuDivider, ContextMenuGroup, and ContextMenuSubMenu. Ignored when items is given. |
Events and template ref
| Name | Signature | Description |
|---|---|---|
openChange | (isOpen: boolean) => void | Fired when the menu opens or closes, before focus moves. |
select | (item: ContextMenuItemData, event: MouseEvent) => void | Fired when a row of the items data API is activated, with the row and the click that activated it. Rows inside a submenu bubble up to the same event. |
update:isOpen | (isOpen: boolean) => void | Listened to by v-model:isOpen; it rarely needs handling by hand. |
element | HTMLElement | null | The trigger element, exposed through a template ref. |
open() | () => void | Opens the menu at the trigger's top-left corner, for a caller with no pointer event to hand. |
close() | () => void | Closes the menu and returns focus to wherever it was before the menu opened. |
focus() / blur() | () => void | Focuses or blurs the trigger element. |
Sub-components
Compound mode and data mode render the same row components, so their styling, keyboard behavior, and theme variables cannot drift apart.
| Component | Props | Description |
|---|---|---|
ContextMenuItem | icon, label, description, endContent, href, target, rel, isDisabled, hasCloseOnSelect, variant | One action row, rendered as role="menuitem". With href the root becomes a real <a>, so a modified click and a middle click keep the browser's meaning. Slots: label, icon, description, endContent; emits click when activated. |
ContextMenuDivider | variant | A rule between groups of rows, rendered as role="separator" so it is never a stop in the arrow order. |
ContextMenuGroup | title | A titled group, rendered as role="group" named by its heading. Slot: default. |
ContextMenuSubMenu | icon, label, description, isDisabled, items | A row that reveals a nested menu, carrying aria-haspopup="menu" and aria-expanded. Use items in data mode or the default slot in compound mode; emits openChange. |
Theming
.my-context-menu {
--astryx-context-menu-background: #ffffff;
--astryx-context-menu-item-focus-background: #0536590c;
}--astryx-context-menu-background: panel background.--astryx-context-menu-foreground: panel text color.--astryx-context-menu-shadow: panel shadow.--astryx-context-menu-item-foreground: row text color.--astryx-context-menu-item-focus-background: background of the highlighted row, for both hover and keyboard focus.--astryx-context-menu-item-pressed-background: background of a row while a mouse holds it down, painted only where hover exists.--astryx-context-menu-item-description-foreground: row description color.--astryx-context-menu-item-error-foreground: label and icon color of avariant="destructive"row.--astryx-context-menu-section-foreground: section heading color.--astryx-context-menu-block-cap: maximum panel height, resolved against the viewport; the default takes the smaller of 300px and the viewport height.--astryx-spacing-1,--astryx-radius-container,--astryx-text-label-size: padding, radius, and type reuse the global tokens.
The neutral theme adapts to light and dark mode on its own.
Native attributes
The root element is the trigger: a <div>, or a <span> with triggerAs="span".
The following go to the trigger element:
- HTML attributes such as
idordata-*. aria-*attributes.
class and style, on the other hand, go to the menu panel: the panel is the painted, themeable surface (the astryx-context-menu class), which mirrors how upstream hands className and style to the menu.
The trigger itself carries no role, aria-haspopup, or aria-expanded: it is not a button, the right-click is a system-level gesture, and the menu is named by its own label only while it is open. The menu panel is teleported to document.body, so it inherits nothing from the trigger; the panel carries its own data-size, data-placement, data-overflow, data-width, and data-astryx-menu-press for styling and tests.