Context Menu
ui-context-menu replaces the browser's context menu inside ui-context-menu-trigger. A right-click (or the context
menu key) on the trigger opens ui-context-menu-content, a popover="auto" menu, at the pointer position and
focuses the first enabled item. The items are the same ui-menu-* parts used by
Dropdown Menu. The arrow keys move between them, Enter or Space chooses one, and choosing
fires select and closes the menu. Escape and a click outside close it too.
Right click here
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Context Menu demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
<style>
.demo-area {
display: grid;
place-content: center;
box-sizing: border-box;
width: min(100%, calc(var(--spacing) * 72));
height: calc(var(--spacing) * 36);
border: 1px dashed var(--border);
border-radius: var(--radius-md);
font-size: var(--text-sm);
color: var(--muted-foreground);
}
</style>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/context-menu.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/dropdown-menu.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/toaster.html"></import-element>
<ui-toaster></ui-toaster>
<ui-context-menu onselect="document.dispatchEvent(new CustomEvent('toast', { detail: { title: 'Chose ' + event.detail.value } }))">
<ui-context-menu-trigger><div class="demo-area">Right click here</div></ui-context-menu-trigger>
<ui-context-menu-content>
<ui-menu-item value="back">Back <ui-menu-shortcut>⌘[</ui-menu-shortcut></ui-menu-item>
<ui-menu-item value="forward" disabled>Forward <ui-menu-shortcut>⌘]</ui-menu-shortcut></ui-menu-item>
<ui-menu-item value="reload">Reload <ui-menu-shortcut>⌘R</ui-menu-shortcut></ui-menu-item>
<ui-menu-separator></ui-menu-separator>
<ui-menu-checkbox-item value="bookmarks" checked>Show Bookmarks</ui-menu-checkbox-item>
<ui-menu-separator></ui-menu-separator>
<ui-menu-label>People</ui-menu-label>
<ui-menu-radio-group value="pedro">
<ui-menu-radio-item value="pedro">Pedro Duarte</ui-menu-radio-item>
<ui-menu-radio-item value="colm">Colm Tuite</ui-menu-radio-item>
</ui-menu-radio-group>
</ui-context-menu-content>
</ui-context-menu>
</body>
</html>Examples
Handle the selection
select bubbles from the chosen item, and event.detail.value is its value.
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Context Menu demo</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/dist/theme.css">
<script type="module" src="https://cdn.jsdelivr.net/npm/@realmorg/realm@alpha/dist/realm.js"></script>
</head>
<body>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/context-menu.html"></import-element>
<import-element from="https://cdn.jsdelivr.net/npm/@realmorg/ui@alpha/components/dropdown-menu.html"></import-element>
<import-element from="./context-menu-file-demo.html"></import-element>
<context-menu-file-demo></context-menu-file-demo>
</body>
</html><custom-element name="context-menu-file-demo">
<script>
const file = useState({ name: "report.pdf", log: "Right click the file." });
const ACTIONS = {
open: (name) => `Opened ${name}.`,
rename: (name) => `Renaming ${name}.`,
delete: (name) => `Deleted ${name}.`,
};
function act(event) {
file.log = ACTIONS[event.detail.value](file.name);
}
</script>
<style>
:host {
display: grid;
justify-items: center;
gap: calc(var(--spacing) * 3);
font-size: var(--text-sm);
}
.file {
display: flex;
align-items: center;
gap: calc(var(--spacing) * 2);
padding: calc(var(--spacing) * 3) calc(var(--spacing) * 4);
border: 1px solid var(--border);
border-radius: var(--radius-md);
}
svg {
width: calc(var(--spacing) * 4);
height: calc(var(--spacing) * 4);
}
output {
color: var(--muted-foreground);
}
</style>
<ui-context-menu onselect="act(event)">
<ui-context-menu-trigger>
<div class="file">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true"><path d="M14 3H6v18h12V7Z" /><path d="M14 3v4h4" /></svg>
<slot name="#file.name"></slot>
</div>
</ui-context-menu-trigger>
<ui-context-menu-content>
<ui-menu-item value="open">Open</ui-menu-item>
<ui-menu-item value="rename">Rename</ui-menu-item>
<ui-menu-separator></ui-menu-separator>
<ui-menu-item value="delete" variant="destructive">Delete</ui-menu-item>
</ui-context-menu-content>
</ui-context-menu>
<output><slot name="#file.log"></slot></output>
</custom-element>API
Parts
| Part | Slot | Renders |
|---|---|---|
ui-context-menu |
Its parts, with no box of its own. | |
ui-context-menu-trigger |
(default) | A block around the area. A contextmenu event inside it opens the menu at the pointer. |
ui-context-menu-content |
(default) | A bordered popover="auto" panel with role="menu", positioned at the pointer with position: fixed. |
ui-menu-* |
(default) | Items, labels, groups, separators and shortcuts. See Dropdown Menu. |
None of the parts has attributes of its own. See Dropdown Menu for the item attributes
(value, disabled, variant, checked).
Events
| Event | Element | Detail | Description |
|---|---|---|---|
select |
ui-menu-item, ui-menu-radio-item |
{ value } |
Fired when an enabled item is chosen. Bubbles to ui-context-menu. The menu closes afterwards. |
select |
ui-menu-checkbox-item |
{ value, checked } |
Same, with the new checked state. |
CSS parts
| Element | Part | Description |
|---|---|---|
ui-context-menu-trigger |
trigger |
The wrapper that listens for contextmenu. |
ui-context-menu-content |
menu |
The focusgroup wrapper around the items. |
Accessibility
- The content has
role="menu"and its itemsrole="menuitem",menuitemcheckboxormenuitemradio. - Opening focuses the first enabled item. Arrow Up and Arrow Down move focus with wrap-around, Home and End jump to the ends, Enter and Space choose, Escape closes.
- The menu opens on any
contextmenuevent from the trigger. Browsers also fire it for the context menu key and Shift+F10 on a focused element, so put a focusable element in the trigger if keyboard users need the menu. Offer the same actions somewhere else as well.