> Markdown version of [Context Menu](https://vaadin.com/docs/next/components/context-menu). Section index: [llms.txt](https://vaadin.com/docs/next/components/llms.txt)

# Context Menu

Context Menu is a component that you can attach to any component to display a context menu. The menu appears on the right by default, or with a left click. On a touch device, a long press opens the context menu.

> **Important:** Open the Context Menu by right-clicking (i.e., with a mouse), or by long-pressing (i.e., on a touch screen), a Grid row.

**Lit** — `context-menu-basic.ts`

```html
@state()
private 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>
```

**Flow** — `ContextMenuBasic.java`

```java
GridContextMenu<Person> menu = grid.addContextMenu();
menu.addItem("View", event -> {
});
menu.addItem("Edit", event -> {
});
menu.addItem("Delete", event -> {
});
```

**React** — `context-menu-basic.tsx`

```tsx
const items = [{ text: 'View' }, { text: 'Edit' }, { text: 'Delete' }];

return (
  <ContextMenu items={items}>
    <Grid allRowsVisible items={gridItems.value} ref={gridRef}>
      <GridColumn path="firstName" />
      <GridColumn path="lastName" />
      <GridColumn path="email" />
      <GridColumn header="Phone number" path="address.phone" />
    </Grid>
  </ContextMenu>
);
```

## <a id="dividers"></a>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 (i.e., with a mouse), or by long-pressing (i.e., on a touch screen), a Grid row.

**Lit** — `context-menu-dividers.ts`

```typescript
<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>
```

**Flow** — `ContextMenuDividers.java`

```java
GridContextMenu<Person> menu = grid.addContextMenu();
menu.addItem("View", event -> {
});
menu.addSeparator();
menu.addItem("Edit", event -> {
});
menu.addItem("Delete", event -> {
});
menu.addSeparator();
menu.addItem("Email", event -> {
});
menu.addItem("Call", event -> {
});
```

**React** — `context-menu-dividers.tsx`

```tsx
<ContextMenu
  items={[
    { text: 'View' },
    { component: 'hr' },
    { text: 'Edit' },
    { text: 'Delete' },
    { component: 'hr' },
    { text: 'Email' },
    { text: 'Call' },
  ]}
>
  <Grid allRowsVisible items={gridItems.value} ref={gridRef}>
    <GridColumn path="firstName" />
    <GridColumn path="lastName" />
    <GridColumn path="email" />
    <GridColumn header="Phone number" path="address.phone" />
  </Grid>
</ContextMenu>
```

## <a id="checkable-menu-items"></a>Checkable Menu Items

Checkable Menu Items can be used to toggle a setting on and off.

**Lit** — `context-menu-checkable.ts`

```typescript
@state()
private items: ContextMenuItemData[] = [
  { 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];
}
```

**Flow** — `ContextMenuCheckable.java`

```java
assignee = new Span();
menu = new ContextMenu();
menu.setTarget(assignee);

List<Person> people = DataService.getPeople(5);
for (Person person : people) {
    MenuItem menuItem = menu.addItem(person.getFullName(), event -> {
        setAssignee(person);
    });
    menuItem.setCheckable(true);
}

setAssignee(people.get(0));

...

private void setAssignee(Person person) {
    // Update checked state of menu items
    menu.getItems().forEach(item -> item
            .setChecked(item.getText().equals(person.getFullName())));

    assignee.setText(person.getFullName());
}
```

**React** — `context-menu-checkable.tsx`

```tsx
const items = useSignal<ContextMenuItemData[]>([
  { text: 'Abigail Lewis', checked: true },
  { text: 'Allison Torres' },
  { text: 'Anna Myers' },
  { text: 'Lauren Wright' },
  { text: 'Tamaki Ryushi' },
]);

const selectedItem = items.value.find((item) => item.checked);

function itemSelected(e: ContextMenuItemSelectedEvent) {
  items.value = items.value.map((item) => ({ ...item, checked: item === e.detail.value }));
}

return (
  <ContextMenu items={items.value} onItemSelected={itemSelected}>
    <span>
      Assignee: <b>{selectedItem?.text}</b>
    </span>
  </ContextMenu>
);
```

## <a id="hierarchical-menu"></a>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 (i.e., with a mouse), or by long-pressing (i.e., on a touch screen), a Grid row.

**Lit** — `context-menu-hierarchical.ts`

```typescript
@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
    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>
```

**Flow** — `ContextMenuHierarchical.java`

```java
GridContextMenu<File> menu = grid.addContextMenu();
GridMenuItem<File> export = menu.addItem("Export");
GridSubMenu<File> exportSubMenu = export.getSubMenu();
exportSubMenu.addItem("Portable Document Format (.pdf)", event -> {
});
exportSubMenu.addItem("Rich Text Format (.rtf)", event -> {
});
exportSubMenu.addItem("Plain text (.txt)", event -> {
});
```

**React** — `context-menu-hierarchical.tsx`

```tsx
const 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' },
];

const gridItems: FileItem[] = [
  { name: 'Annual Report.docx', size: '24 MB' },
  { name: 'Financials.xlsx', size: '42 MB' },
];

return (
  <ContextMenu items={items}>
    <Grid allRowsVisible items={gridItems} ref={gridRef}>
      <GridColumn path="name" />
      <GridColumn path="size" />
    </Grid>
  </ContextMenu>
);
```

## <a id="tooltips"></a>Tooltips (since V25.2)

Menu items can be configured with tooltips to provide additional information.

**Lit** — `context-menu-tooltip.ts`

```typescript
@state()
private items = [
  { text: 'Edit', tooltip: 'Edit selected person' },
  {
    text: 'Share',
    children: [
      { text: 'Copy link', tooltip: 'Copy a shareable link to the clipboard' },
      {
        text: 'Email',
        tooltip: 'Send the contact details by email',
        tooltipPosition: 'end',
      },
    ],
  },
];

...

<vaadin-context-menu .items=${this.items}>
  <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
  <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>
</vaadin-context-menu>
```

**Flow** — `ContextMenuTooltip.java`

```java
GridContextMenu<Person> menu = grid.addContextMenu();
GridMenuItem<Person> edit = menu.addItem("Edit");
edit.setTooltipText("Edit selected person");

GridMenuItem<Person> share = menu.addItem("Share");
GridSubMenu<Person> shareSubMenu = share.getSubMenu();
shareSubMenu.addItem("Copy link")
        .setTooltipText("Copy a shareable link to the clipboard");
GridMenuItem<Person> email = shareSubMenu.addItem("Email");
email.setTooltipText("Send the contact details by email");
email.setTooltipPosition(TooltipPosition.END);
```

**React** — `context-menu-tooltip.tsx`

```tsx
const items = [
  { text: 'Edit', tooltip: 'Edit selected person' },
  {
    text: 'Share',
    children: [
      { text: 'Copy link', tooltip: 'Copy a shareable link to the clipboard' },
      {
        text: 'Email',
        tooltip: 'Send the contact details by email',
        tooltipPosition: 'end',
      },
    ],
  },
];

return (
  <ContextMenu items={items}>
    <Tooltip slot="tooltip" />
    <Grid allRowsVisible items={gridItems.value} ref={gridRef}>
      <GridColumn path="firstName" />
      <GridColumn path="lastName" />
      <GridColumn path="email" />
    </Grid>
  </ContextMenu>
);
```

See the [Tooltips documentation page](https://vaadin.com/docs/next/components/tooltip.md) for details on tooltip configuration.

Tooltips are also useful on disabled menu items to explain why an action is unavailable, but they are not shown by default. See [Disabled Menu Items](#disabled-menu-items) for how to enable them.

## <a id="custom-items"></a>Custom Items

You can customize the items to include more than a single line of text.

> **Important:** Open the Context Menu by right-clicking (i.e., with a mouse), or by long-pressing (i.e., on a touch screen), a Grid row.

**Lit** — `context-menu-presentation.ts`

```typescript
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>
```

**Flow** — `ContextMenuPresentation.java`

```java
GridContextMenu<Person> menu = grid.addContextMenu();
GridMenuItem<Person> assign = menu.addItem("Assign");
assign.addComponentAsFirst(createIcon(VaadinIcon.USER_CHECK));

GridSubMenu<Person> assignSubMenu = assign.getSubMenu();
people.subList(5, 10).forEach(person -> {
    assignSubMenu.addItem(createPersonItem(person), event -> {
    });
});

// ...

private Component createPersonItem(Person person) {
    Avatar avatar = new Avatar(person.getFullName(),
            person.getPictureUrl());
    Span name = new Span(person.getFullName());
    Span profession = new Span(person.getProfession());

    Div personItem = new Div(avatar, name, profession);
    personItem.addClassName("person-item");
    return personItem;
}
```

**React** — `context-menu-presentation.tsx`

```tsx
const contextMenuItems: ContextMenuItemData[] = [
      { component: createItem('vaadin:file-search', 'Open') },
      {
        component: createItem('vaadin:user-check', 'Assign'),
        children: [
          {
            component: <Item person={people[0]} />,
          },
          {
            component: <Item person={people[1]} />,
          },
          {
            component: <Item person={people[2]} />,
          },
          {
            component: <Item person={people[3]} />,
          },
          {
            component: <Item person={people[4]} />,
          },
        ],
      },
      { component: 'hr' },
      { component: createItem('vaadin:trash', 'Delete') },
    ];

    items.value = contextMenuItems;
return (
  <ContextMenu items={items.value}>
    <Grid allRowsVisible items={gridItems.value} ref={gridRef}>
      <GridColumn header="Applicant" renderer={renderApplicant} />
      <GridColumn path="email" />
      <GridColumn header="Phone number" path="address.phone" />
    </Grid>
  </ContextMenu>
);
```

`person-item.css`

```css
.person-item {
    display: grid;
    grid-template-columns: min-content auto;
    grid-template-rows: auto auto;
    grid-template-areas:
        "avatar name"
        "avatar title";
    gap: 0 var(--vaadin-gap-s);
    align-items: center;
    line-height: 1.2;

    & > :is(vaadin-avatar, img) {
        grid-area: avatar;
    }

    & > span:first-of-type {
        grid-area: name;
    }

    & > span:last-of-type {
        grid-area: title;
        font-size: 0.875rem;
        font-weight: 400;
        color: var(--vaadin-text-color-secondary);
    }
}
```

## <a id="styling-menu-items"></a>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.

**Lit** — `context-menu-classname.ts`

```typescript
@state()
private items: ContextMenuItemData[] = [
  { text: 'Share' },
  { text: 'Duplicate' },
  { text: 'Delete', className: 'custom' },
];
```

**Flow** — `ContextMenuClassname.java`

```java
MenuItem item = menu.addItem("Delete");
item.setClassName("custom");
```

**React** — `context-menu-classname.tsx`

```tsx
const items = useSignal<ContextMenuItemData[]>([
  { text: 'Share' },
  { text: 'Duplicate' },
  { text: 'Delete', className: 'custom' },
]);
```

`context-menu-class-name.css`

```css
vaadin-context-menu-item.custom {
   color: red;
}
```

## <a id="disabled-menu-items"></a>Disabled Menu Items

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

> **Important:** Open the Context Menu by right-clicking (i.e., with a mouse), or by long-pressing (i.e., on a touch screen), a Grid row.

**Lit** — `context-menu-disabled.ts`

```typescript
@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
    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>
```

**Flow** — `ContextMenuDisabled.java`

```java
GridContextMenu<File> menu = grid.addContextMenu();

GridMenuItem<File> export = menu.addItem("Export");
GridSubMenu<File> exportSubMenu = export.getSubMenu();
GridMenuItem<File> exportPDF = exportSubMenu
        .addItem("Portable Document Format (.pdf)", event -> {
        });
exportPDF.setEnabled(false);

GridMenuItem<File> delete = menu.addItem("Delete", event -> {
});
delete.setEnabled(false);
```

**React** — `context-menu-disabled.tsx`

```tsx
const 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 },
];

const gridItems: FileItem[] = [
  { name: 'Annual Report.pdf', size: '24 MB' },
  { name: 'Financials.pdf', size: '42 MB' },
];

return (
  <ContextMenu items={items}>
    <Grid allRowsVisible items={gridItems} ref={gridRef}>
      <GridColumn path="name" />
      <GridColumn path="size" />
    </Grid>
  </ContextMenu>
);
```

By default, disabled menu items aren’t focusable or hoverable, which hides them from assistive technologies and prevents Tooltips on disabled items from showing. The `accessibleDisabledMenuItems` (since V25.2) feature flag can be enabled to make them focusable and hoverable without allowing them to be triggered:

`Flow`

```properties
# Add this line to src/main/resources/vaadin-featureflags.properties
com.vaadin.experimental.accessibleDisabledMenuItems=true
```

`Lit & React`

```js
// Set before any menu is added to the DOM
window.Vaadin.featureFlags.accessibleDisabledMenuItems = true;
```

### <a id="disable-on-click-flow"></a>Disable on Click (Flow)

To prevent duplicate clicks while the server is processing a request, call the `setDisableOnClick(true)` method on a menu item instance to disable immediately that menu item on the client-side when it’s clicked.

**Flow** — `ContextMenuDisableOnClick.java`

```java
MenuItem summarize = menu.addItem("Summarize with AI");
summarize.setDisableOnClick(true);
```

## <a id="left-click"></a>Left-Click

You can use left-click to open Context Menu in situations where left-click doesn’t have any other function (e.g., a Grid without selection support).

> **Important:** Open the Context Menu by clicking a Grid row.

**Lit** — `context-menu-left-click.ts`

```typescript
@state()
private 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>
```

**Flow** — `ContextMenuLeftClick.java`

```java
GridContextMenu<Person> menu = grid.addContextMenu();
menu.setOpenOnClick(true);
menu.addItem("View", event -> {
});
menu.addItem("Edit", event -> {
});
menu.addItem("Delete", event -> {
});
```

**React** — `context-menu-left-click.tsx`

```tsx
return (
  <ContextMenu openOn="click" items={items.value}>
    <Grid allRowsVisible items={gridItems.value} ref={gridRef}>
      <GridColumn path="firstName" />
      <GridColumn path="lastName" />
      <GridColumn path="email" />
      <GridColumn header="Phone number" path="address.phone" />
    </Grid>
  </ContextMenu>
);
```

## <a id="custom-item-data"></a>Custom Item Data

Context Menu allows you to associate custom data with menu items. This can be useful for storing additional information about the item, such as an item type or a value. The data can then be used to trigger actions when an item is selected.

**Lit** — `context-menu-custom-item-data.ts`

```typescript
@state()
private items: Array<ContextMenuItemData<{ value: string }>> = [
  {
    text: 'Copy as plain text',
    value:
      'Context Menu\n\nContext Menu is a component that you can attach to any component to display a context menu.',
  },
  {
    text: 'Copy as HTML',
    value:
      '<h1>Context Menu</h1><p>Context Menu is a component that you can attach to any component to display a context menu.</p>',
  },
  {
    text: 'Copy as Markdown',
    value:
      '# Context Menu\n\nContext Menu is a component that you can attach to any component to display a context menu.',
  },
];

protected override render() {
  return html`
    <vaadin-context-menu .items="${this.items}" @item-selected="${this.itemSelected}">
      <h1>Context Menu</h1>
      <p>
        Context Menu is a component that you can attach to any component to display a context
        menu.
      </p>
    </vaadin-context-menu>
  `;
}

itemSelected(e: ContextMenuItemSelectedEvent<ContextMenuItemData<{ value?: string }>>) {
  const { value } = e.detail.value;
  if (value) {
    navigator.clipboard.writeText(value);
  }
}
```

**Flow** — `ContextMenuCustomItemData.java`

```java
Div wrapper = new Div(new H1("Context Menu"), new Paragraph(
        "Menu Bar is a horizontal button bar with hierarchical drop-down menus."));

ContextMenu menu = new ContextMenu();
menu.setTarget(wrapper);

menu.addItem("Copy as plain text", event -> {
    // Provide a custom value by adding a click listener that holds a
    // reference to that value
    String value = "Menu Bar\n\nMenu Bar is a horizontal button bar with hierarchical drop-down menus.";
    copyToClipboard(value);
});

menu.addItem("Copy as HTML", event -> {
    String value = "<h1>Menu Bar</h1><p>Menu Bar is a horizontal button bar with hierarchical drop-down menus.</p>";
    copyToClipboard(value);
});

menu.addItem("Copy as Markdown", event -> {
    String value = "# Menu Bar\n\nMenu Bar is a horizontal button bar with hierarchical drop-down menus.";
    copyToClipboard(value);
});
```

**React** — `context-menu-custom-item-data.tsx`

```tsx
const items: Array<ContextMenuItemData<{ value: string }>> = [
  {
    text: 'Copy as plain text',
    value:
      'Context Menu\n\nContext Menu is a component that you can attach to any component to display a context menu.',
  },
  {
    text: 'Copy as HTML',
    value:
      '<h1>Context Menu</h1><p>Context Menu is a component that you can attach to any component to display a context menu.</p>',
  },
  {
    text: 'Copy as Markdown',
    value:
      '# Context Menu\n\nContext Menu is a component that you can attach to any component to display a context menu.',
  },
];

return (
  <ContextMenu
    items={items}
    onItemSelected={(event) => {
      const { value } = event.detail.value;
      if (value) {
        navigator.clipboard.writeText(value);
      }
    }}
  >
    <h1>Context Menu</h1>
    <p>
      Context Menu is a component that you can attach to any component to display a context menu.
    </p>
  </ContextMenu>
);
```

## <a id="best-practices"></a>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 (i.e., for desktops) or long-pressing (i.e., for mobile devices) a Grid row, or use the Menu Bar in the last column.

**Lit** — `context-menu-best-practices.ts`

```typescript
@state()
private 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>
```

**Flow** — `ContextMenuBestPractices.java`

```java
grid.addComponentColumn(file -> {
    MenuBar menuBar = new MenuBar();
    menuBar.addThemeVariants(MenuBarVariant.TERTIARY);
    menuBar.addItem("Preview", event -> {
    });
    menuBar.addItem("Edit", event -> {
    });
    menuBar.addItem("Delete", event -> {
    });
    return menuBar;
}).setWidth("70px").setFlexGrow(0);

GridContextMenu<File> menu = grid.addContextMenu();
menu.addItem("Preview", event -> {
});
menu.addItem("Edit", event -> {
});
menu.addItem("Delete", event -> {
});
```

**React** — `context-menu-best-practices.tsx`

```tsx
<ContextMenu items={items.value}>
  <Grid allRowsVisible items={gridItems.value}>
    <GridColumn path="name" />
    <GridColumn path="size" />
    <GridColumn width="70px" flexGrow={0} renderer={renderMenuBar} />
  </Grid>
</ContextMenu>
```

### <a id="context-menu-vs-menu-bar"></a>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 or component, such as an [overflow menu](https://vaadin.com/docs/next/components/menu-bar.md), use Menu Bar.

### <a id="icons"></a>Icons

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

### <a id="labelling"></a>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.

## <a id="related-components"></a>Related Components

| Component                                                       | Usage Recommendations                                                  |
| --------------------------------------------------------------- | ---------------------------------------------------------------------- |
| [Menu Bar](https://vaadin.com/docs/next/components/menu-bar.md) | Component for displaying a horizontal menu with multi-level sub-menus. |
| [Popover](https://vaadin.com/docs/next/components/popover.md)   | A generic overlay whose position is anchored to an element in the UI.  |

`760AB528-B02C-4B6C-BB27-D7EFEDAE706E`
