Context Menu
- Usage
- Styling
Context Menu is a component that you can attach to any component to display a context menu. The menu appears on right (default) or left click. On a touch device, a long press opens the context menu.
Important
| Open the Context Menu by right-clicking (mouse) or long-pressing (touch) a Grid row. |
new tab
@state()
private accessor items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];
<!-- ... -->
<vaadin-context-menu .items=${this.items}>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column path="firstName"></vaadin-grid-column>
<vaadin-grid-column path="lastName"></vaadin-grid-column>
<vaadin-grid-column path="email"></vaadin-grid-column>
<vaadin-grid-column header="Phone number" path="address.phone"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Dividers
You can use dividers to separate and group related content. Use dividers sparingly to avoid creating unnecessary visual clutter.
Important
| Open the Context Menu by right-clicking (mouse) or long-pressing (touch) a Grid row. |
new tab
<vaadin-context-menu
.items=${[
{ text: 'View' },
{ component: 'hr' },
{ text: 'Edit' },
{ text: 'Delete' },
{ component: 'hr' },
{ text: 'Email' },
{ text: 'Call' },
]}
>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column path="firstName"></vaadin-grid-column>
<vaadin-grid-column path="lastName"></vaadin-grid-column>
<vaadin-grid-column path="email"></vaadin-grid-column>
<vaadin-grid-column header="Phone number" path="address.phone"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Checkable Menu Items
Checkable Menu Items can be used to toggle a setting on and off.
new tab
@state()
private accessor items: ContextMenuItem[] = [
{ text: 'Abigail Lewis', checked: true },
{ text: 'Allison Torres' },
{ text: 'Anna Myers' },
{ text: 'Lauren Wright' },
{ text: 'Tamaki Ryushi' },
];
protected override render() {
const selectedItem = this.items.find((item) => item.checked);
return html`
<vaadin-context-menu .items="${this.items}" @item-selected="${this.itemSelected}">
<span>Assignee: <b>${selectedItem?.text}</b></span>
</vaadin-context-menu>
`;
}
itemSelected(e: ContextMenuItemSelectedEvent) {
this.items.forEach((item) => {
item.checked = item === e.detail.value;
});
this.items = [...this.items];
}
Hierarchical Menu
Context Menu, like Menu Bar, supports multi-level sub-menus. You can use a hierarchical menu to organize a large set of options and group related items.
Important
| Open the Context Menu by right-clicking (mouse) or long-pressing (touch) a Grid row. |
new tab
@state()
private accessor items = [
{ text: 'Preview' },
{ text: 'Edit' },
{ component: 'hr' },
{
text: 'Export',
children: [
{ text: 'Portable Document Format (.pdf)' },
{ text: 'Rich Text Format (.rtf)' },
{ text: 'Plain text (.txt)' },
],
},
{ text: 'Share', children: [{ text: 'Copy link' }, { text: 'Email' }] },
{ component: 'hr' },
{ text: 'Delete' },
];
// ...
<vaadin-context-menu .items=${this.items}>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column path="name"></vaadin-grid-column>
<vaadin-grid-column path="size"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Custom Items
You can customize the items to include more than a single line of text.
Important
| Open the Context Menu by right-clicking (mouse) or long-pressing (touch) a Grid row. |
new tab
protected override async firstUpdated() {
const { people } = await getPeople({ count: 10 });
this.gridItems = people.slice(0, 5);
const itemsArray = this.createItemsArray(people.slice(5, 10));
this.items = [
{ component: this.createItem('vaadin:file-search', 'Open') },
{
component: this.createItem('vaadin:user-check', 'Assign'),
children: [
{ component: itemsArray[0] },
{ component: itemsArray[1] },
{ component: itemsArray[2] },
{ component: itemsArray[3] },
{ component: itemsArray[4] },
],
},
{ component: 'hr' },
{ component: this.createItem('vaadin:trash', 'Delete') },
];
}
...
<vaadin-context-menu .items=${this.items}>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column
header="Applicant"
${columnBodyRenderer<Person>(
(person) => html`<span>${person.firstName} ${person.lastName}</span>`,
[]
)}
></vaadin-grid-column>
<vaadin-grid-column path="email"></vaadin-grid-column>
<vaadin-grid-column header="Phone number" path="address.phone"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Styling Menu Items
Individual menu items can be styled by applying custom class names to them, and writing CSS style blocks targeting those class names.
new tab
@state()
private accessor items: ContextMenuItem[] = [
{ text: 'Share' },
{ text: 'Duplicate' },
{ text: 'Delete', className: 'text-error' },
];
Note
|
Use theme names instead of class names in V24.2 and older
In versions prior to 24.3, theme names must be used instead (theme property / addThemeNames Java method). The CSS syntax for targeting a theme name is [theme~="custom-theme"]
|
Disabled Menu Items
You can disable menu items to show that they are unavailable.
Important
| Open the Context Menu by right-clicking (mouse) or long-pressing (touch) a Grid row. |
new tab
@state()
private accessor items = [
{ text: 'Preview' },
{ text: 'Edit' },
{ component: 'hr' },
{
text: 'Export',
children: [
{ text: 'Portable Document Format (.pdf)', disabled: true },
{ text: 'Rich Text Format (.rtf)' },
{ text: 'Plain text (.txt)' },
],
},
{ text: 'Share', children: [{ text: 'Copy link' }, { text: 'Email' }] },
{ component: 'hr' },
{ text: 'Delete', disabled: true },
];
// ...
<vaadin-context-menu .items=${this.items}>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column path="name"></vaadin-grid-column>
<vaadin-grid-column path="size"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Left-Click
You can use left-click to open Context Menu in situations where left-click doesn’t have any other function, for example a Grid without selection support.
Important
| Open the Context Menu by clicking a Grid row. |
new tab
@state()
private accessor items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];
// ...
<vaadin-context-menu
open-on="click"
.items=${this.items}
@opened-changed="${(event: ContextMenuOpenedChangedEvent) => {
this.contextMenuOpened = event.detail.value;
}}"
>
<vaadin-grid all-rows-visible .items=${this.gridItems} @click=${this.onClick}>
<vaadin-grid-column path="firstName"></vaadin-grid-column>
<vaadin-grid-column path="lastName"></vaadin-grid-column>
<vaadin-grid-column path="email"></vaadin-grid-column>
<vaadin-grid-column header="Phone number" path="address.phone"></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Best Practices
Context Menu is used to provide shortcuts to the user. You shouldn’t use it as the only or primary means to complete a task. The primary way should be accessible elsewhere in the UI.
Important
| Open the Context Menu by right-clicking (desktop) or long-pressing (mobile) a Grid row, or use the Menu Bar in the last column. |
new tab
@state()
private accessor items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];
// ...
<vaadin-context-menu .items=${this.items}>
<vaadin-grid
all-rows-visible
.items=${this.gridItems}
@vaadin-contextmenu=${this.onContextMenu}
>
<vaadin-grid-column path="name"></vaadin-grid-column>
<vaadin-grid-column path="size"></vaadin-grid-column>
<vaadin-grid-column
width="70px"
flex-grow="0"
${columnBodyRenderer(
() => html`
<vaadin-menu-bar .items=${this.items} theme="tertiary"></vaadin-menu-bar>
`,
[]
)}
></vaadin-grid-column>
</vaadin-grid>
</vaadin-context-menu>
Context Menu vs Menu Bar
You should use Context Menu when there is no dedicated button for opening an overlay menu, such as right-clicking a grid row. When there is a dedicated element/component, such as an overflow menu, use Menu Bar.
Related Components
Component | Usage recommendations |
---|---|
Component for displaying a horizontal menu with multi-level sub-menus. |
760AB528-B02C-4B6C-BB27-D7EFEDAE706E