Skip to main content
Vuetify0 Logo
Theme
Mode
Palettes
Accessibility
Vuetify One
Sign in to Vuetify One

Access premium tools across the Vuetify ecosystem — Bin, Play, Studio, and more.

Not a subscriber? See what's included

Menu

Menu opens a list of actions from a button, a right-click, or a horizontal bar. Submenus, checkable items, and keyboard navigation are part of the same component.

Edit this page
Report a Bug
Open issues
View on GitHub
Copy Markdown

PreviewRenderlessIntermediateOct 18, 2026
Browser Support: CSS Anchor Positioning
Chrome 125+ Edge 125+ Firefox 147+ Safari 26+

The menu works in every browser. Automatic placement needs CSS Anchor Positioning. Without it, install the popover plugin with the shipped FloatingUIPopoverAdapter (@vuetify/v0/popover/adapters/floating-ui).

Usage

Theme
Mode
Palettes
Accessibility
<script setup lang="ts">
  import { Menu } from '@vuetify/v0'
</script>

<template>
  <div class="flex justify-center">
    <Menu.Root>
      <Menu.Activator class="px-4 py-2 bg-primary text-on-primary rounded-md text-sm font-medium">
        Actions
      </Menu.Activator>

      <Menu.Content class="min-w-40 rounded-md border border-divider bg-surface p-1 shadow-lg">
        <Menu.Item class="rounded px-3 py-2 text-sm text-on-surface data-[highlighted]:bg-surface-variant">
          Copy
        </Menu.Item>

        <Menu.Item class="rounded px-3 py-2 text-sm text-on-surface data-[highlighted]:bg-surface-variant">
          Paste
        </Menu.Item>
      </Menu.Content>
    </Menu.Root>
  </div>
</template>

Anatomy

vue
<script setup lang="ts">
  import { Menu } from '@vuetify/v0'
</script>

<template>
  <Menu.Root>
    <Menu.Bar>
      <Menu.Activator />
    </Menu.Bar>

    <Menu.Context />

    <Menu.Content>
      <Menu.Item />

      <Menu.CheckboxItem />

      <Menu.RadioGroup>
        <Menu.RadioItem />
      </Menu.RadioGroup>

      <Menu.Separator />

      <Menu.Sub>
        <Menu.SubActivator />

        <Menu.SubContent>
          <Menu.Item />
        </Menu.SubContent>
      </Menu.Sub>
    </Menu.Content>
  </Menu.Root>
</template>

Examples

A submenu is one component you place inside Menu.Content. ShareMenu.vue is only Menu.Sub, its activator, and its content. submenu.vue puts that component next to New file. The submenu renders inside the parent menu, so it shares the open path: Arrow Left returns to Share, and the File menu stays open. A second Menu.Root is a separate menu and does not share that path.

The chevron is part of ShareMenu. Menu.SubActivator sets aria-haspopup="menu" and aria-expanded. It does not paint an icon. Draw the indicator yourself so the item shows that it opens another menu. rtl:-scale-x-100 mirrors the glyph in RTL. The submenu still opens on the inline-end side. The glyph only marks the item.

Resting the pointer on Share opens the submenu after open-delay (default 100ms), even when open-on-hover is off. Arrow Right opens it and focuses Email. Arrow Left closes that layer and returns focus to Share. Pass position-area when the submenu should open somewhere else. The placement example reuses this same component and does that.

FileRole
ShareMenu.vueNested menu, including the chevron
submenu.vueFile menu that places ShareMenu inside its content
Theme
Mode
Palettes
Accessibility

Context menu

Menu.Context is the right-click target. Menu.Content is its sibling. A right-click on Copy or Paste then stays a click on that item. Putting the content inside the target would open the menu again from the item.

DocumentActions.vue is the list. Each item emits the name of the action it ran. An action item closes the menu, so the page cannot read the choice while the menu is open. context.vue stores the name and prints it after the menu is gone. A checkbox or a radio stays open. That pattern is the next example.

Escape closes the menu and returns focus to Menu.Context. There is no long-press.

FileRole
DocumentActions.vueCopy and Paste. Each emits the action it ran
context.vueRight-click target, the menu beside it, and the last-action line
Right-click this area

Last action: None

Theme
Mode
Palettes
Accessibility

value names a layer. v-model is which layer is open. A single menu sets value on Menu.Root when the page opens that menu by id, and the activator and content omit it.

Each menu on the bar is one record: an id, a label, and its items. menubar.vue loops that list twice. The activators live inside Menu.Bar. The contents are siblings of the bar. Both use the record’s id as value, so File opens the File menu and Edit opens the Edit menu. Adding a menu means adding a record. The loops pick it up.

Keep Menu.Content outside Menu.Bar. The bar is role="menubar". A menu nested inside it would be a menu inside the menubar. The root slot’s layer is the id of the menu that is open, or null. The line under the bar turns that id back into a label, which is how you show which menu is open without reading the DOM.

Arrow keys move across the bar. Arrow Down opens the focused menu on its first item. Arrow Up opens it on its last. With open-on-hover left off, hovering a closed bar does nothing. Once a menu is open, hovering another activator switches to it immediately.

FileRole
menus.tsOne record per menu: id, label, and items
menubar.vueBar and menus from that list, plus the line that names the open menu

Showing nothing

Theme
Mode
Palettes
Accessibility

Checkbox and radio

selection.vue owns the values. FormatMenu.vue only binds them. Menu.CheckboxItem uses v-model:checked. Menu.RadioGroup uses v-model, and each Menu.RadioItem writes its value. Checking Bold or Right leaves the menu open, so the line under the button updates while the menu is still up. An action item closes the menu. The context example is that case.

The box and the dot are drawn from data-state on the item. The item does not paint a control. Put group on the item and group-data-[state=checked] on the indicator. data-state is checked or unchecked. A class on an inner element does not see that attribute.

Disabled items ignore the pointer and the keyboard. The page can still change the model, which is why the refs live in selection.vue.

FileRole
FormatMenu.vueFormat menu. Binds bold and align, and draws the box and the dot
selection.vueOwns the two values and prints them

Bold off, aligned left.

Theme
Mode
Palettes
Accessibility

Placement and options

The values, the controls, and the menu are three pieces. usePlacement holds the values and pick(). PlacementControls.vue is ordinary inputs. ActionsMenu.vue receives the values as props and passes them to Menu.Root and Menu.Content. options.vue only connects the three. Change a control while the menu is open and the open menu follows it.

position-area on Menu.Content takes a CSS position-area↗︎ value. bottom opens under the button. top, left, right, and the corners (top left, bottom right) place the menu in that cell of the anchor. position-try is the fallback when that cell does not fit. The default is most-width bottom.

ShareMenu.vue is the submenu from the first example. ActionsMenu passes position-area into it, so the submenu side is a prop on the component you already wrote. Menu.SubContent defaults to inline-end span-block-start when you omit the prop.

The direction buttons sit outside the menu. Clicking one light-dismisses an open menu before the new value is visible, so pick() writes the area and opens the menu again on the next turn. Keep those buttons out of the cells the menu will cover. A menu that opens under the pointer highlights the item there, and Share then starts its open delay.

open-on-hover, open-delay, and close-delay are props on Menu.Root. With hover open, the pointer rests for open-delay before the menu opens, and leaving closes it after close-delay. A click or a key still opens immediately. disabled blocks every activator and item in that menu.

FileRole
usePlacement.tsThe values, and the click that reopens after light-dismiss
PlacementControls.vueFallback, submenu side, delays, and the direction grid
ShareMenu.vueThe submenu from the first example, placed by a prop
ActionsMenu.vueThe menu. Receives those values and passes them through
options.vueConnects the controls to the menu
Activator

position-area: bottom
position-try: most-width bottom

Theme
Mode
Palettes
Accessibility

Accessibility

Menu.Content and Menu.SubContent are role="menu". Items are menuitem, menuitemcheckbox, or menuitemradio. Menu.Bar is role="menubar". Separators are role="separator".

A menu opened from an activator is named by that activator. A context menu with no activator uses the locale string Menu.label.

A click, a right-click, or a pointer switch opens the menu with no item highlighted. Moving the pointer onto an item highlights that item. Arrow Down then highlights the first item, and Arrow Up highlights the last. Arrow keys on a closed activator still open straight onto the first or last item, and Enter or Space opens onto the first item.

KeyMenuMenubar
Arrow Down / UpOn a closed activator, Arrow Down opens the first item and Arrow Up opens the last. Inside the open menu, Down and Up move between itemsOn a closed activator, Arrow Down opens the first item and Arrow Up opens the last. Inside the open menu, Down and Up move between items
Home / EndMoves to the first or last itemMoves to the first or last activator
Arrow RightOpens a submenu, or moves to the next menu when more than one activator is registered. It does not close the top menuOpens a submenu, or moves to the next menu when more than one activator is registered. It does not close the top menu
Arrow LeftCloses one submenu, or moves to the previous menu when more than one activator is registered. It does not close the top menuCloses one submenu, or moves to the previous menu when more than one activator is registered. It does not close the top menu
Enter / SpaceOn a closed activator, opens the first item. On a submenu item, opens that submenu and leaves the menu open. On an action item, runs the action and closes. On a checkbox or radio, changes the value and stays openToggles the focused menu. On an item, same as Menu
EscapeCloses every layer and returns focus to the activator. A context menu has no activator. Focus returns to the Menu.Context elementCloses every layer and returns focus to the activator
TabCloses every layer and moves focus to the next control. It does not return focus to the activator, and it does not prevent the browser’s default TabCloses every layer and moves focus to the next control. It does not return focus to the activator, and it does not prevent the browser’s default Tab
TypeaheadFocuses the item whose label starts with the typed textSame, on the open menu

Arrow Left and Arrow Right swap in RTL. Typeahead ignores Space, which activates the focused item, and it resets after a short pause.

FAQ

Discord
Need help? Join our community for support and discussions ↗
Was this page helpful?

© 2016-1970 Vuetify, LLC
Services
Ctrl+/