ContextMenu
Right-click activated menu with items, submenus, checkbox and radio items.
?
| Name | Category | Description | Type | Default |
|---|---|---|---|---|
maxHeight | ? Style | Max menu height, scrollable when exceeded | number | string | — |
hoverColor | ? Style | Custom hover background color for items | string | — |
ContextMenuItemdivided | ? Style | Show divider above | boolean | false |
disabled | ? State | Whether to disable context menu | boolean | false |
ContextMenuItemdisabled | ? State | Whether disabled | boolean | false |
ContextMenuCheckboxItemdisabled | ? State | Whether disabled | boolean | false |
ContextMenuRadioItemdisabled | ? State | Whether disabled | boolean | false |
ContextMenuSubdisabled | ? State | Whether disabled | boolean | false |
hideOnClick | ? Behavior | Whether to close after item click | boolean | true |
lockScroll | ? Behavior | Whether to lock page scroll when menu is open | boolean | false |
↑ / ↓ | ? Behavior | Move focus between items (skip disabled) | — | |
Enter / Space | ? Behavior | Select the focused item | — | |
→ | ? Behavior | Open submenu | — | |
← | ? Behavior | Close submenu, return to parent | — | |
Escape | ? Behavior | Close menu | — | |
Home / End | ? Behavior | Jump to first/last enabled item | — | |
items | ? Content | Menu items (shorthand) | ContextMenuItemDef[] | — |
ContextMenuItemcommand | ? Content | Command identifier | string | number | — |
ContextMenuItemlabel | ? Content | Display text | string | VNode | — |
ContextMenuItemicon | ? Content | Icon name | string | — |
ContextMenuItemshortcut | ? Content | Shortcut hint, e.g. ["Ctrl", "C"] | string[] | — |
ContextMenuCheckboxItemmodelValue / v-model | ? Content | Whether checked | boolean | false |
ContextMenuCheckboxItemlabel | ? Content | Display text | string | VNode | — |
ContextMenuRadioGroupmodelValue / v-model | ? Content | Currently selected value | string | — |
ContextMenuRadioItemvalue | ? Content | Option value (required) | string | — |
ContextMenuRadioItemlabel | ? Content | Display text | string | VNode | — |
ContextMenuSublabel | ? Content | Submenu trigger text | string | VNode | — |
ContextMenuSubicon | ? Content | Icon name | string | — |
ContextMenuSubitems | ? Content | Submenu items (shorthand) | ContextMenuItemDef[] | — |
command | ? Event | Triggered when item is clicked | (command: string | number) => void | — |
visible-change | ? Event | Triggered when menu shows/hides | (visible: boolean) => void | — |
default | ? Slot | Right-click trigger area | — | |
content | ? Slot | Menu content, composed with sub-components | — | |
open | ? Expose | Programmatically open menu | (event: MouseEvent) => void | — |
close | ? Expose | Close menu | () => void | — |
Basic Usage
Right-click the trigger area to open the context menu. Use the items prop for quick setup.
<template>
<px-context-menu :items="items" @command="handleCommand">
<div class="demo-area">
Right-click here
</div>
</px-context-menu>
</template>
<script setup lang="ts">
import { PxMessage } from 'sakana-element';
const items = [
{ label: 'Cut', command: 'cut' },
{ label: 'Copy', command: 'copy' },
{ label: 'Paste', command: 'paste' },
{ label: 'Delete', command: 'delete', divided: true },
];
const handleCommand = (command: string) => {
PxMessage.info(`Command: ${command}`);
};
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>Slot-Based Composition
Use sub-components in the content slot for full control: labels, separators, icons, and keyboard shortcuts.
<template>
<px-context-menu @command="handleCommand">
<div class="demo-area">
Right-click for slot-based menu
</div>
<template #content>
<px-context-menu-label>Edit</px-context-menu-label>
<px-context-menu-item label="Undo" command="undo" :shortcut="['Ctrl', 'Z']" />
<px-context-menu-item label="Redo" command="redo" :shortcut="['Ctrl', 'Y']" />
<px-context-menu-separator />
<px-context-menu-item label="Cut" command="cut" icon="cut" :shortcut="['Ctrl', 'X']" />
<px-context-menu-item label="Copy" command="copy" icon="clipboard" :shortcut="['Ctrl', 'C']" />
<px-context-menu-item label="Paste" command="paste" :shortcut="['Ctrl', 'V']" />
</template>
</px-context-menu>
</template>
<script setup lang="ts">
import { PxMessage } from 'sakana-element';
const handleCommand = (command: string) => {
PxMessage.info(`Command: ${command}`);
};
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>Submenu
Nest menus with PxContextMenuSub. Submenus open on hover with a slight delay.
<template>
<px-context-menu @command="handleCommand">
<div class="demo-area">
Right-click for submenu
</div>
<template #content>
<px-context-menu-item label="Back" command="back" />
<px-context-menu-item label="Forward" command="forward" />
<px-context-menu-item label="Reload" command="reload" :shortcut="['Ctrl', 'R']" />
<px-context-menu-separator />
<px-context-menu-sub label="More Tools">
<px-context-menu-item label="Save Page As..." command="save" :shortcut="['Ctrl', 'S']" />
<px-context-menu-item label="Create Shortcut" command="shortcut" />
<px-context-menu-item label="Developer Tools" command="devtools" :shortcut="['F12']" />
</px-context-menu-sub>
</template>
</px-context-menu>
</template>
<script setup lang="ts">
import { PxMessage } from 'sakana-element';
const handleCommand = (command: string) => {
PxMessage.info(`Command: ${command}`);
};
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>Disabled Items
Set disabled on individual items to prevent interaction.
<template>
<px-context-menu @command="handleCommand">
<div class="demo-area">
Right-click — some items disabled
</div>
<template #content>
<px-context-menu-item label="Cut" command="cut" />
<px-context-menu-item label="Copy" command="copy" />
<px-context-menu-item label="Paste" command="paste" disabled />
<px-context-menu-item label="Delete" command="delete" disabled />
</template>
</px-context-menu>
</template>
<script setup lang="ts">
import { PxMessage } from 'sakana-element';
const handleCommand = (command: string) => {
PxMessage.info(`Command: ${command}`);
};
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>Checkbox Items
Use PxContextMenuCheckboxItem with v-model for toggle items. Set hide-on-click to false to keep the menu open.
<template>
<px-context-menu :hide-on-click="false">
<div class="demo-area">
Right-click for checkbox items
</div>
<template #content>
<px-context-menu-label>View</px-context-menu-label>
<px-context-menu-checkbox-item v-model="showToolbar" label="Toolbar" />
<px-context-menu-checkbox-item v-model="showStatusBar" label="Status Bar" />
<px-context-menu-checkbox-item v-model="showMinimap" label="Minimap" />
</template>
</px-context-menu>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const showToolbar = ref(true);
const showStatusBar = ref(true);
const showMinimap = ref(false);
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>Radio Items
Wrap PxContextMenuRadioItem in a PxContextMenuRadioGroup with v-model for exclusive selection.
<template>
<px-context-menu :hide-on-click="false">
<div class="demo-area">
Right-click for radio items
</div>
<template #content>
<px-context-menu-label>Theme</px-context-menu-label>
<px-context-menu-radio-group v-model="theme">
<px-context-menu-radio-item label="Light" value="light" />
<px-context-menu-radio-item label="Dark" value="dark" />
<px-context-menu-radio-item label="System" value="system" />
</px-context-menu-radio-group>
</template>
</px-context-menu>
</template>
<script setup lang="ts">
import { ref } from 'vue';
const theme = ref('light');
</script>
<style scoped>
.demo-area {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
min-height: 120px;
border: 2px dashed var(--px-border-color);
font-family: var(--px-font-family);
color: var(--px-text-color-secondary);
}
</style>