Context Menu is a component that you can attach to any component to display a context menu that appears on right (default) or left click. In a mobile browser, a long press opens the context menu.

Important
Open the Context Menu by right-clicking (desktop) or long-pressing (mobile) a Grid row.
@state()
private items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];

...

<vaadin-context-menu .items=${this.items}>
  <vaadin-grid
    height-by-rows
    .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 (desktop) or long-pressing (mobile) a Grid row.
<vaadin-context-menu
  .items=${[
    { text: 'View' },
    { component: 'hr' },
    { text: 'Edit' },
    { text: 'Delete' },
    { component: 'hr' },
    { text: 'Email' },
    { text: 'Call' },
  ]}
>
  <vaadin-grid
    height-by-rows
    .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.

@state()
private items: ContextMenuItem[] = [
  { text: 'Abigail Lewis' },
  { text: 'Allison Torres' },
  { text: 'Anna Myers' },
  { text: 'Lauren Wright' },
  { text: 'Tamaki Ryushi' },
];

@state()
private selectedItem = this.items[1];

...

<vaadin-context-menu
  .items="${this.items.map((item) => {
    return { ...item, checked: item === this.selectedItem };
  })}"
  @item-selected="${this.itemSelected}"
>
  <span>Assignee: <b>${this.selectedItem?.text}</b></span>
</vaadin-context-menu>

...

itemSelected(e: ContextMenuItemSelectedEvent) {
  this.selectedItem = this.items.find(
    (item) => item.text === e.detail.value.text
  ) as ContextMenuItem;
}

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 (desktop) or long-pressing (mobile) a Grid row.
@state()
private 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
    height-by-rows
    .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 (desktop) or long-pressing (mobile) a Grid row.
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
    height-by-rows
    .items=${this.gridItems}
    @vaadin-contextmenu=${this.onContextMenu}
  >
    <vaadin-grid-column
      header="Applicant"
      .renderer=${this.nameRenderer}
    ></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>

Disabled Menu Items

You can disable menu items to show that they are unavailable.

Important
Open the Context Menu by right-clicking (desktop) or long-pressing (mobile) a Grid row.
@state()
private 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
    height-by-rows
    .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 does not have any other function, for example a Grid without selection support.

Important
Open the Context Menu by clicking a Grid row.
@state()
private items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];

...

<vaadin-context-menu
  open-on="click"
  .items=${this.items}
  @opened-changed=${(e: ContextMenuOpenedChangedEvent) =>
    (this.contextMenuOpened = e.detail.value)}
>
  <vaadin-grid height-by-rows .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 should not 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.
@state()
private items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];

...

<vaadin-context-menu .items=${this.items}>
  <vaadin-grid
    height-by-rows
    .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
      auto-width
      flex-grow="0"
      .renderer="${this.menuBarRenderer}"
    ></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.

Icons

Use icons when applicable to help improve recognition. It is recommended to use commonly recognized icons to avoid confusion. Use icons consistently throughout a list of options.

Labelling

Suffix a menu item with “…​” when the associated action won’t be executed, but instead reveal some UI, like a dialog, for completing the action.

ComponentUsage recommendations

Menu Bar

Component for displaying a horizontal menu with multi-level sub-menus.