Documentation

Documentation versions (currently viewingVaadin 24)

Menu Bar

Menu Bar is a horizontal button bar with hierarchical drop-down menus.

Menu Bar is a horizontal button bar with hierarchical drop-down menus. Menu items can trigger an action, open a menu, or work as a toggle.

Open in a
new tab
@state()
private accessor items = [
  { text: 'View' },
  { text: 'Edit' },
  {
    text: 'Share',
    children: [
      {
        text: 'On social media',
        children: [{ text: 'Facebook' }, { text: 'Twitter' }, { text: 'Instagram' }],
      },
      { text: 'By email' },
      { text: 'Get link' },
    ],
  },
  {
    text: 'Move',
    children: [{ text: 'To folder' }, { text: 'To trash' }],
  },
  { text: 'Duplicate' },
];

@state()
private accessor selectedItem: MenuBarItem | undefined;
    <vaadin-menu-bar
      .items="${this.items}"
      @item-selected="${this.itemSelected}"
    ></vaadin-menu-bar>

    <div>Clicked item: ${this.selectedItem?.text}</div>

Styles

Default Variants

The following variants are available to adjust the appearance of the component:

Open in a
new tab
<vaadin-menu-bar
  .items="${[{ text: 'Default', children: [{ text: 'Item' }] }]}"
></vaadin-menu-bar>
<vaadin-menu-bar
  theme="tertiary"
  .items="${[{ text: 'Tertiary', children: [{ text: 'Item' }] }]}"
></vaadin-menu-bar>
<vaadin-menu-bar
  theme="primary"
  .items="${[{ text: 'Primary', children: [{ text: 'Item' }] }]}"
></vaadin-menu-bar>
<vaadin-menu-bar
  theme="small"
  .items="${[{ text: 'Small', children: [{ text: 'Item' }] }]}"
></vaadin-menu-bar>
Variant Usage Recommendation

Tertiary

Corresponds to the tertiary button variant, omitting the background color.

Primary

Corresponds to the primary button variant. Since only one primary action should be presented in the same part of the UI, this should be used only for drop-down button use cases.

Small

Compact variant. Can be combined with Tertiary and Primary.

Tip
Customize Default Menu Button Styles
The standard Menu Button styles can be adjusted using the Lumo style properties. These variants should be used only to differentiate special instances of the component.

Alignment

Top-level items are aligned by default to the start of the Menu Bar. Use instead the end-aligned theme variant to align them to the end.

Open in a
new tab
<vaadin-menu-bar theme="end-aligned" .items="${this.items}"></vaadin-menu-bar>

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. Notice that root-level menu items in the Menu Bar are wrapped in vaadin-menu-bar-button elements, which inherit the class names from the items within them.

Open in a
new tab
@state()
private accessor items = [
  { text: 'View', className: 'bg-primary text-primary-contrast' },
  { text: 'Edit' },
  {
    text: 'Share',
    children: [
      { text: 'By email', className: 'bg-primary text-primary-contrast' },
      { text: 'Get link' },
    ],
  },
];

protected override render() {
  return html`<vaadin-menu-bar .items="${this.items}"></vaadin-menu-bar>`;
}
Note
Use Theme Names, Not Class Names pre-V24.3
In versions prior to 24.3, theme names must be used instead of class names (theme property / addThemeNames Java method). The CSS syntax for targeting a theme name is [theme~="custom-theme"]

Overflow

Items that don’t fit into the current width of the menu bar collapse into an overflow menu at the end:

Open in a
new tab
@state()
private accessor items = [
  { text: 'View' },
  { text: 'Edit' },
  {
    text: 'Share',
    children: [
      {
        text: 'On social media',
        children: [{ text: 'Facebook' }, { text: 'Twitter' }, { text: 'Instagram' }],
      },
      { text: 'By email' },
      { text: 'Get link' },
    ],
  },
  {
    text: 'Move',
    children: [{ text: 'To folder' }, { text: 'To trash' }],
  },
  { text: 'Duplicate' },
];
    <vaadin-split-layout>
      <vaadin-menu-bar .items="${this.items}"></vaadin-menu-bar>
      <div>Move the splitter to see overflow feature</div>
    </vaadin-split-layout>

Several features are available for menu items. They’re described in the following sub-sections.

Icons

Menu items can have icons in addition to text — or instead of text.

Open in a
new tab
@state()
private accessor items = [
  {
    component: this.createItem('share', 'Share'),
    children: [
      { component: this.createItem('share', 'By email', true) },
      { component: this.createItem('link', 'Get link', true) },
    ],
  },
  {
    component: this.createItem('copy', ''),
  },
];
    <vaadin-menu-bar theme="icon" .items="${this.items}"></vaadin-menu-bar>

Most actions are difficult to represent reliably with icons, so use them sparingly. The benefit of icons in addition to text should be weighed against the visual distractions they may create. Menu items in drop-down menus should always have text labels.

Icon-only menu buttons should be used primarily for common recurring actions with highly standardized, universally understood icons. Menu buttons should include a textual alternative for screen readers using the aria-label attribute or tooltips. Menu Bars with icon-only top-level items can use the Tertiary Inline style variant to reduce the horizontal padding around the icons.

Open in a
new tab
@state()
private accessor items = [
  { component: this.createItem('eye', 'View') },
  { component: this.createItem('pencil', 'Edit') },
  {
    component: this.createItem('share', 'Share'),
    children: [
      {
        text: 'On social media',
        children: [{ text: 'Facebook' }, { text: 'Twitter' }, { text: 'Instagram' }],
      },
      { text: 'By email' },
      { text: 'Get link' },
    ],
  },
  {
    component: this.createItem('folder', 'Move'),
    children: [{ text: 'To folder' }, { text: 'To trash' }],
  },
  { component: this.createItem('copy', 'Duplicate') },
];
    <vaadin-menu-bar theme="tertiary-inline" .items="${this.items}"></vaadin-menu-bar>
Warning
Other Components in Menu Items
While it’s technically possible to put any UI element in a menu item, this can cause problems for accessibility as it may not be possible to focus them, and they may not be interpreted correctly by assistive technologies.

Disabled Items

Menu items can be disabled to show that they are unavailable currently.

Open in a
new tab
@state()
private accessor items = [
  { text: 'View' },
  { text: 'Edit', disabled: true },
  {
    text: 'Share',
    children: [{ text: 'By email', disabled: true }, { text: 'Get link' }],
  },
];

Checkable Menu Items

Menu items in drop-down menus can be configured as checkable to toggle options on and off.

Open in a
new tab
@state()
private accessor items = [
  {
    text: 'Options',
    children: [{ text: 'Save automatically', checked: true }, { text: 'Notify watchers' }],
  },
];
    <vaadin-menu-bar
      .items="${this.items}"
      @item-selected="${this.itemSelected}"
    ></vaadin-menu-bar>
itemSelected(e: MenuBarItemSelectedEvent) {
  const item = e.detail.value;
  (item as SubMenuItem).checked = !(item as SubMenuItem).checked;
}
Note
Not a Radio Button Replacement
A Menu Bar with checkable items shouldn’t be used as a replacement for radio buttons in a form.

Dividers

You can use dividers to separate and group related content. However, use dividers sparingly to avoid creating unnecessary visual clutter.

Open in a
new tab
@state()
private accessor items = [
  {
    text: 'Share',
    children: [
      { text: 'Facebook' },
      { text: 'Twitter' },
      { text: 'Instagram' },
      { component: 'hr' },
      { text: 'By email' },
      { text: 'Get link' },
      { component: 'hr' },
      { text: 'Set permissions' },
    ],
  },
];
    <vaadin-menu-bar .items="${this.items}"></vaadin-menu-bar>
Warning
Other Content Not Accessible
While it’s technically possible to put any UI element in a drop-down menu — including interactive components — they’re not accessible by keyboard or assistive technologies.

Open on Hover

A component can be configured to open drop-down menus on hover, instead of on click.

Open in a
new tab
@state()
private accessor items = [
  { text: 'View' },
  { text: 'Edit' },
  {
    text: 'Share',
    children: [
      {
        text: 'On social media',
        children: [{ text: 'Facebook' }, { text: 'Twitter' }, { text: 'Instagram' }],
      },
      { text: 'By email' },
      { text: 'Get link' },
    ],
  },
  {
    text: 'Move',
    children: [{ text: 'To folder' }, { text: 'To trash' }],
  },
  { text: 'Duplicate' },
];
    <vaadin-menu-bar .items="${this.items}" open-on-hover></vaadin-menu-bar>

Tooltips

Tooltips can be configured on top-level items to provide additional information, especially for icon-only items. When a top-level item is disabled, the corresponding tooltip isn’t shown.

Open in a
new tab
@state()
private accessor items = [
  {
    component: this.createItem('eye'),
    tooltip: 'View',
  },
  {
    component: this.createItem('pencil'),
    tooltip: 'Edit',
  },
  {
    component: this.createItem('folder'),
    tooltip: 'Move',
  },
  {
    component: this.createItem('copy'),
    tooltip: 'Duplicate',
  },
  {
    component: this.createItem('archive'),
    tooltip: 'Archive',
    disabled: true,
  },
];

...

<vaadin-menu-bar .items="${this.items}" theme="icon">
  <vaadin-tooltip slot="tooltip"></vaadin-tooltip>
</vaadin-menu-bar>

See the Tooltips documentation page for details on tooltip configuration.

Keyboard Usage

Top-Level Items

Interaction Keyboard Shortcut

Navigate between top-level items.

Left and Right arrow keys

Open top-level menu.

Down / Space / Enter

Trigger top-level item with a menu.

Space / Enter

Interaction Keyboard Shortcut

Navigate between items in a drop-down menu.

Up and Down arrow keys

Open sub-menu.

Right / Space / Enter

Trigger menu item without a sub-menu.

Space / Enter

Return to previous menu.

Left

Close the drop-down menu.

Esc

A Menu Bar with a single top-level item is essentially a drop-down button. This solution provides a better user experience and better accessibility than a regular Button paired with a Context Menu.

Open in a
new tab
@state()
private accessor items = [
  {
    text: 'John Smith',
    children: [
      { text: 'Profile' },
      { text: 'Account' },
      { text: 'Preferences' },
      { component: 'hr' },
      { text: 'Sign out' },
    ],
  },
];
    <vaadin-menu-bar .items="${this.items}"></vaadin-menu-bar>

So-called combo buttons can be created in a similar way. For example, they can be created to provide a set of variations on an action.

Open in a
new tab
@state()
private accessor items = [
  { text: 'Save' },
  {
    component: this.createItem(),
    children: [{ text: 'Save as draft' }, { text: 'Save as copy' }, { text: 'Save and publish' }],
  },
];
    <vaadin-menu-bar theme="icon primary" .items="${this.items}"></vaadin-menu-bar>

Internationalization (i18n)

Menu Bar provides an API for localization. Currently, only the accessible label for the overflow menu button can be customized.

const customI18n: MenuBarI18n = {
  // Provide accessible label for the overflow menu button
  // to screen readers
  moreOptions: 'More actions',
};

return html`<vaadin-menu-bar .i18n="${customI18n}" .items="${this.items}"></vaadin-menu-bar>`;

Best Practices

Menu Bar shouldn’t be used for navigation. Use tabs to switch between content, or anchor elements for regular navigation. It isn’t an input field. Use instead Select, Combo Box, or Radio Button.

Menu Bar is an interactive component. Using other interactive components like Combo Box as menu items is not advised as this may produce conflicts in keyboard navigation and interaction. Although items are children of Menu Bar, it’s not supposed to act as a layout component.

Component Usage Recommendation

Button

Regular Button component for individual actions.

Select

Drop-down input field.

Tabs

Tabs should be used to split content into sections that the user can switch between.

Context Menu

A generic drop-down menu that can be triggered from any component.

BCC76FD2-FB02-4F71-A6DF-7574CAC1C662