ContextMenu
Description
<vaadin-context-menu>
is a Web Component for creating context menus.
Items
Items is a higher level convenience API for defining a (hierarchical) menu structure for the component.
If a menu item has a non-empty children
set, a sub-menu with the child items is opened
next to the parent menu on mouseover, tap or a right arrow keypress.
When an item is selected, <vaadin-context-menu>
dispatches an "item-selected" event
with the selected item as event.detail.value
property.
If item does not have keepOpen
property the menu will be closed.
contextMenu.items = [
{ text: 'Menu Item 1', theme: 'primary', className: 'first', children:
[
{ text: 'Menu Item 1-1', checked: true, keepOpen: true },
{ text: 'Menu Item 1-2' }
]
},
{ component: 'hr' },
{ text: 'Menu Item 2', children:
[
{ text: 'Menu Item 2-1' },
{ text: 'Menu Item 2-2', disabled: true }
]
},
{ text: 'Menu Item 3', disabled: true, className: 'last' }
];
contextMenu.addEventListener('item-selected', e => {
const item = e.detail.value;
console.log(`${item.text} selected`);
});
NOTE: when the items
array is defined, the renderer cannot be used.
Rendering
The content of the menu can be populated by using the renderer callback function.
The renderer function provides root
, contextMenu
, model
arguments when applicable.
Generate DOM content by using model
object properties if needed, append it to the root
element and control the state of the host element by accessing contextMenu
. Before generating
new content, the renderer function should check if there is already content in root
for reusing it.
<vaadin-context-menu id="contextMenu">
<p>This paragraph has a context menu.</p>
</vaadin-context-menu>
const contextMenu = document.querySelector('#contextMenu');
contextMenu.renderer = (root, contextMenu, context) => {
let listBox = root.firstElementChild;
if (!listBox) {
listBox = document.createElement('vaadin-list-box');
root.appendChild(listBox);
}
let item = listBox.querySelector('vaadin-item');
if (!item) {
item = document.createElement('vaadin-item');
listBox.appendChild(item);
}
item.textContent = 'Content of the selector: ' + context.target.textContent;
};
You can access the menu context inside the renderer using
context.target
and context.detail
.
Renderer is called on the opening of the context-menu and each time the related context is updated.
DOM generated during the renderer call can be reused
in the next renderer call and will be provided with the root
argument.
On first call it will be empty.
vaadin-contextmenu
Gesture Event
vaadin-contextmenu
is a gesture event (a custom event),
which is dispatched after either contextmenu
or long touch events.
This enables support for both mouse and touch environments in a uniform way.
<vaadin-context-menu>
opens the menu overlay on the vaadin-contextmenu
event by default.
Menu Listener
By default, the <vaadin-context-menu>
element listens for the menu opening
event on itself. In case if you do not want to wrap the target, you can listen for
events on an element outside the <vaadin-context-menu>
by setting the
listenOn
property:
<vaadin-context-menu id="contextMenu"></vaadin-context-menu>
<div id="menuListener">The element that listens for the contextmenu event.</div>
const contextMenu = document.querySelector('#contextMenu');
contextMenu.listenOn = document.querySelector('#menuListener');
Filtering Menu Targets
By default, the listener element and all its descendants open the context
menu. You can filter the menu targets to a smaller set of elements inside
the listener element by setting the selector
property.
In the following example, only the elements matching .has-menu
will open the context menu:
<vaadin-context-menu selector=".has-menu">
<p class="has-menu">This paragraph opens the context menu</p>
<p>This paragraph does not open the context menu</p>
</vaadin-context-menu>
Menu Context
The following properties are available in the context
argument:
target
is the menu opening event target, which is the element that the user has called the context menu fordetail
is the menu opening event detail
In the following example, the menu item text is composed with the contents of the element that opened the menu:
<vaadin-context-menu selector="li" id="contextMenu">
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Baz</li>
</ul>
</vaadin-context-menu>
const contextMenu = document.querySelector('#contextMenu');
contextMenu.renderer = (root, contextMenu, context) => {
let listBox = root.firstElementChild;
if (!listBox) {
listBox = document.createElement('vaadin-list-box');
root.appendChild(listBox);
}
let item = listBox.querySelector('vaadin-item');
if (!item) {
item = document.createElement('vaadin-item');
listBox.appendChild(item);
}
item.textContent = 'The menu target: ' + context.target.textContent;
};
Styling
The following shadow DOM parts are available for styling:
Part name | Description |
---|---|
backdrop |
Backdrop of the overlay |
overlay |
The overlay container |
content |
The overlay content |
See Styling Components documentation.
Internal components
When using items
API the following internal components are themable:
<vaadin-context-menu-item>
- has the same API as<vaadin-item>
.<vaadin-context-menu-list-box>
- has the same API as<vaadin-list-box>
.
The <vaadin-context-menu-item>
sub-menu elements have the following additional state attributes
on top of the built-in <vaadin-item>
state attributes:
Attribute | Description |
---|---|
expanded |
Expanded parent item. |
Properties
closeOn
Type: string
Event name to listen for closing the context menu.
items
Type: ContextMenuItem[] | undefined
Defines a (hierarchical) menu structure for the component.
If a menu item has a non-empty children
set, a sub-menu with the child items is opened
next to the parent menu on mouseover, tap or a right arrow keypress.
The items API can't be used together with a renderer!
Example
contextMenu.items = [
{ text: 'Menu Item 1', theme: 'primary', className: 'first', children:
[
{ text: 'Menu Item 1-1', checked: true, keepOpen: true },
{ text: 'Menu Item 1-2' }
]
},
{ component: 'hr' },
{ text: 'Menu Item 2', children:
[
{ text: 'Menu Item 2-1' },
{ text: 'Menu Item 2-2', disabled: true }
]
},
{ text: 'Menu Item 3', disabled: true, className: 'last' }
];
See also: ContextMenuItem
listenOn
Type: HTMLElement
The target element that's listened to for context menu opening events.
By default the vaadin-context-menu listens to the target's vaadin-contextmenu
events.
opened
Type: boolean
True if the overlay is currently displayed.
openOn
Type: string
Event name to listen for opening the context menu.
renderer
Type: ContextMenuRenderer | null | undefined
Custom function for rendering the content of the menu overlay. Receives three arguments:
root
The root container DOM element. Append your content to it.contextMenu
The reference to the<vaadin-context-menu>
element.context
The object with the menu context, contains:context.target
the target of the menu opening event,context.detail
the menu opening event detail.
See also: ContextMenuRenderer
selector
Type: string | null | undefined
CSS selector that can be used to target any child element
of the context menu to listen for openOn
events.
Methods
close
Type: () => void
Closes the overlay.
open
Type: (e: Event | undefined) => void
Opens the overlay.
requestContentUpdate
Type: () => void
Requests an update for the content of the menu overlay.
While performing the update, it invokes the renderer passed in the renderer
property.
It is not guaranteed that the update happens immediately (synchronously) after it is requested.
Events
closed
Type: ContextMenuClosedEvent
Fired when the context menu is closed.
item-selected
Type: ContextMenuItemSelectedEvent
Fired when an item is selected when the context menu is populated using the items
API.
opened-changed
Type: ContextMenuOpenedChangedEvent
Fired when the opened
property changes.
Types
ContextMenuClosedEvent
/**
* Fired when the context menu is closed.
*/
export type ContextMenuClosedEvent = CustomEvent;
ContextMenuItem
export type ContextMenuItem<TItemData extends object = object> = {
text?: string;
component?: HTMLElement | string;
disabled?: boolean;
checked?: boolean;
keepOpen?: boolean;
theme?: string[] | string;
className?: string;
children?: Array<ContextMenuItem<TItemData>>;
} & TItemData;
ContextMenuItemSelectedEvent
/**
* Fired when an item is selected when the context menu is populated using the `items` API.
*/
export type ContextMenuItemSelectedEvent<TItem extends ContextMenuItem = ContextMenuItem> = CustomEvent<{
value: TItem;
}>;
ContextMenuOpenedChangedEvent
/**
* Fired when the `opened` property changes.
*/
export type ContextMenuOpenedChangedEvent = CustomEvent<{ value: boolean }>;
ContextMenuRenderer
export type ContextMenuRenderer = (
root: HTMLElement,
contextMenu: ContextMenu,
context: ContextMenuRendererContext,
) => void;
ContextMenuRendererContext
export interface ContextMenuRendererContext {
target: HTMLElement;
detail?: { sourceEvent: Event };
}