Component
Context menu
<DomContextMenu>A right-click menu built on the shared menu primitive.
Demo
Right-click menu
Context menus use the same DomMenu item model, including keyboard navigation and destructive tones.
Right click this panel to open the context menu.
Selected: none
Rows.vuevue
<script setup>
import { ref } from 'vue';
import { DomContextMenu } from '@getdom/studio/vue';
const selected = ref('none');
const items = [
{ label: 'Open', value: 'open' },
{ label: 'Rename', value: 'rename' },
{ label: 'Duplicate', value: 'duplicate' },
{ separator: true },
{ label: 'Delete', value: 'delete', tone: 'danger' },
];
</script>
<template>
<div class="w-full max-w-md space-y-3">
<DomContextMenu :items="items" @select="selected = $event.value">
<div class="rounded-2xl border border-dashed border-border bg-secondary/30 p-6 text-center text-sm text-muted-fg">
Right click this panel to open the context menu.
</div>
</DomContextMenu>
<p class="text-xs text-muted-fg">Selected: <code class="text-fg">{{ selected }}</code></p>
</div>
</template>
Nested
Context menu with submenus
Use the same children array as DomMenu to create hoverable and keyboard-accessible nested context menu items.
Quarterly plan
Right click this row to open nested actions.
Owner
Maya Patel
Status
In review
Updated
Today
Selected: none
Nested.vuevue
<script setup>
import { ref } from 'vue';
import { DomContextMenu } from '@getdom/studio/vue';
const selected = ref('none');
const items = [
{ label: 'Open', value: 'open' },
{ label: 'Rename', value: 'rename' },
{ label: 'Duplicate', value: 'duplicate' },
{
label: 'Move to',
value: 'move',
children: [
{ label: 'Inbox', value: 'move-inbox' },
{ label: 'Archive', value: 'move-archive' },
{ label: 'Projects', value: 'move-projects' },
],
},
{
label: 'Share',
value: 'share',
children: [
{ label: 'Email', value: 'share-email' },
{ label: 'SMS', value: 'share-sms' },
{ label: 'Instagram', value: 'share-instagram' },
],
},
{ separator: true },
{ label: 'Delete', value: 'delete', tone: 'danger' },
];
</script>
<template>
<div class="w-full max-w-lg space-y-3">
<DomContextMenu :items="items" @select="selected = $event.value">
<div class="overflow-hidden rounded-2xl border border-border bg-background text-sm shadow-sm">
<div class="grid grid-cols-[1fr_auto] gap-4 border-b border-border skin-raised px-4 py-3 backdrop-blur">
<div>
<p class="font-medium text-fg">Quarterly plan</p>
<p class="mt-1 text-xs text-muted-fg">Right click this row to open nested actions.</p>
</div>
<span class="self-start rounded-full bg-success/15 px-2.5 py-1 text-xs font-medium text-success">Live</span>
</div>
<div class="grid gap-2 p-4 text-muted-fg sm:grid-cols-3">
<div>
<p class="text-xs uppercase tracking-[0.14em]">Owner</p>
<p class="mt-1 text-fg">Maya Patel</p>
</div>
<div>
<p class="text-xs uppercase tracking-[0.14em]">Status</p>
<p class="mt-1 text-fg">In review</p>
</div>
<div>
<p class="text-xs uppercase tracking-[0.14em]">Updated</p>
<p class="mt-1 text-fg">Today</p>
</div>
</div>
</div>
</DomContextMenu>
<p class="text-xs text-muted-fg">Selected: <code class="text-fg">{{ selected }}</code></p>
</div>
</template>
Reference
Props
Control props
| Name | Type | TS | Default | Description |
|---|---|---|---|---|
items* | array | Array<unknown> | — | Context menu rows. Use children for nested menus. |
width | string | string | 'min-w-48' | Tailwind width utility for the menu panel. |
lockScroll | boolean | boolean | true | Lock browser scrolling while the context menu is open. |
openOnContextMenu | boolean | boolean | true | Open automatically when the default slot is right-clicked. Disable when opening from another component event. |
Auto-generated from Context menu.props and inline _edit hints.
Events
| Name | Payload | Description |
|---|---|---|
| @open | ({ event }) | Fired when the menu is opened. |
| @select | ({ value, item }) | Fired when a menu item is selected. |
Names auto-detected from defineEmits and source emit() calls; payload and description from __doc.events when present.