Menubar
<script setup lang="ts">
import { Icon } from '@iconify/vue'
import { ref } from 'vue'
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarMenu,
MenubarPortal,
MenubarRadioGroup,
MenubarRadioItem,
MenubarRoot,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from 'radix-vue'
const currentMenu = ref('')
const checkboxOne = ref(false)
const checkboxTwo = ref(false)
const person = ref('pedro')
function handleClick() {
alert('hello!')
}
const RADIO_ITEMS = ['Andy', 'Benoît', 'Luis']
const CHECK_ITEMS = ['Always Show Bookmarks Bar', 'Always Show Full URLs']
</script>
<template>
<MenubarRoot v-model="currentMenu" class="flex bg-white p-[3px] rounded-md shadow-[0_2px_10px] shadow-blackA7">
<MenubarMenu value="file">
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-grass11 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-green4 data-[state=open]:bg-green4"
>
File
</MenubarTrigger>
<MenubarPortal>
<MenubarContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
align="start"
:side-offset="5"
:align-offset="-3"
>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
New Tab
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⌘ T
</div>
</MenubarItem>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
New Window
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⌘ N
</div>
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
disabled
>
New Incognito Window
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarSub>
<MenubarSubTrigger
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Share
<div
class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
>
<Icon icon="radix-icons:chevron-right" />
</div>
</MenubarSubTrigger>
<MenubarPortal>
<MenubarSubContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
:align-offset="-5"
>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Email Link
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Messages
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Notes
</MenubarItem>
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Print…
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⌘ P
</div>
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-grass11 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-green4 data-[state=open]:bg-green4"
>
Edit
</MenubarTrigger>
<MenubarPortal>
<MenubarContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
align="start"
:side-offset="5"
:align-offset="-3"
>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Undo
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⌘ Z
</div>
</MenubarItem>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Redo
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⇧ ⌘ Z
</div>
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarSub>
<MenubarSubTrigger
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find
<div
class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
>
<Icon icon="radix-icons:chevron-right" />
</div>
</MenubarSubTrigger>
<MenubarPortal>
<MenubarSubContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
:align-offset="-5"
>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Search the web…
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find…
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find Next
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find Previous
</MenubarItem>
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Cut
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Copy
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Paste
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-grass11 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-green4 data-[state=open]:bg-green4"
>
View
</MenubarTrigger>
<MenubarPortal>
<MenubarContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
align="start"
:side-offset="5"
:align-offset="-14"
>
<MenubarCheckboxItem
v-model="checkboxOne"
class="group text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[20px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
>
<MenubarItemIndicator class="absolute left-0 w-[20px] inline-flex items-center justify-center">
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
Show Bookmarks
<div
class="ml-auto pl-[20px] text-mauve11 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
>
⌘+B
</div>
</MenubarCheckboxItem>
<MenubarCheckboxItem
v-model="checkboxTwo"
class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[20px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
>
<MenubarItemIndicator class="absolute left-0 w-[20px] inline-flex items-center justify-center">
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
Show Full URLs
</MenubarCheckboxItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Reload
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⌘ R
</div>
</MenubarItem>
<MenubarItem
class="group text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
disabled
>
Force Reload
<div class="ml-auto pl-5 text-mauve9 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8">
⇧ ⌘ R
</div>
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Toggle Fullscreen
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Hide Sidebar
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
<MenubarMenu>
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-grass11 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-green4 data-[state=open]:bg-green4"
>
Profiles
</MenubarTrigger>
<MenubarPortal>
<MenubarContent
class="min-w-[220px] outline-none bg-white rounded-md p-[5px] shadow-[0px_10px_38px_-10px_rgba(22,_23,_24,_0.35),_0px_10px_20px_-15px_rgba(22,_23,_24,_0.2)] [animation-duration:_400ms] [animation-timing-function:_cubic-bezier(0.16,_1,_0.3,_1)] will-change-[transform,opacity]"
align="start"
:side-offset="5"
:align-offset="-14"
>
<MenubarRadioGroup v-model="person">
<MenubarRadioItem
class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[20px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
value="pedro"
>
<MenubarItemIndicator class="absolute left-0 w-[20px] inline-flex items-center justify-center">
<Icon icon="radix-icons:dot-filled" />
</MenubarItemIndicator>
Pedro Duarte
</MenubarRadioItem>
<MenubarRadioItem
class="text-[13px] leading-none text-grass11 rounded-[3px] flex items-center h-[25px] px-[5px] relative pl-[20px] select-none outline-none data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none data-[highlighted]:bg-green9 data-[highlighted]:text-green1"
value="colm"
>
<MenubarItemIndicator class="absolute left-0 w-[20px] inline-flex items-center justify-center">
<Icon icon="radix-icons:dot-filled" />
</MenubarItemIndicator>
Colm Tuite
</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
@click="handleClick"
>
Edit…
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-green6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-grass11 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-green4 data-[state=open]:text-grass11 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-green9 data-[highlighted]:to-green10 data-[highlighted]:text-green1 data-[highlighted]:data-[state=open]:text-green1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Add Profile…
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>Features
- Can be controlled or uncontrolled.
- Supports submenus with configurable reading direction.
- Supports items, labels, groups of items.
- Supports checkable items (single or multiple).
- Customize side, alignment, offsets, collision handling.
- Optionally render a pointing arrow.
- Focus is fully managed.
- Full keyboard navigation.
- Typeahead support.
Installation
Install the component from your command line.
npm install radix-vueAnatomy
Import all parts and piece them together.
<script setup lang="ts">
import {
MenubarArrow,
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarLabel,
MenubarMenu,
MenubarPortal,
MenubarRadioGroup,
MenubarRadioItem,
MenubarRoot,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from './'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger />
<MenubarPortal>
<MenubarContent>
<MenubarLabel />
<MenubarItem />
<MenubarGroup>
<MenubarItem />
</MenubarGroup>
<MenubarCheckboxItem>
<MenubarItemIndicator />
</MenubarCheckboxItem>
<MenubarRadioGroup>
<MenubarRadioItem>
<MenubarItemIndicator />
</MenubarRadioItem>
</MenubarRadioGroup>
<MenubarSub>
<MenubarSubTrigger />
<MenubarPortal>
<MenubarSubContent />
</MenubarPortal>
</MenubarSub>
<MenubarSeparator />
<MenubarArrow />
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>API Reference
Root
Contains all the parts of a menubar
| Prop | Default | Type |
|---|---|---|
defaultValue | stringThe value of the menu that should be open when initially rendered. Use when you do not need to control the value state. | |
dir | DirectionThe reading direction of the combobox when applicable. If omitted, inherits globally from | |
loop | false | booleanWhen |
modelValue | stringThe controlled value of the menu to open. Can be used as |
| Emit | Type |
|---|---|
update:modelValue | [value: boolean] |
Menu
A top level menu item, contains a trigger with content combination.
| Prop | Default | Type |
|---|---|---|
value | stringA unique value that associates the item with an active value when the navigation menu is controlled. This prop is managed automatically when uncontrolled. |
Trigger
The button that toggles the content. By default, the MenubarContent will position itself against the trigger.
| Prop | Default | Type |
|---|---|---|
as | 'button' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
disabled | booleanWhen |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Portal
When used, portals the content part into the body.
| Prop | Default | Type |
|---|---|---|
disabled | booleanDisable teleport and render the component inline {@link https://vuejs.org/guide/built-ins/teleport.html#disabling-teleport} | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
to | string | HTMLElementVue native teleport component props. (to) {@link https://vuejs.org/guide/built-ins/teleport.html#basic-usage} |
Content
The component that pops out when a menu is open.
| Prop | Default | Type |
|---|---|---|
align | 'start' | 'start' | 'center' | 'end'The preferred alignment against the trigger. May change when collisions occur. |
alignOffset | numberAn offset in pixels from the "start" or "end" alignment options. | |
arrowPadding | numberThe padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. | |
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
avoidCollisions | booleanWhen | |
collisionBoundary | Element | (Element | null)[] | nullThe element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. | |
collisionPadding | number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
hideWhenDetached | booleanWhether to hide the content when the trigger becomes fully occluded. | |
loop | booleanWhen | |
side | 'top' | 'right' | 'bottom' | 'left'The preferred side of the trigger to render against when open. Will be reversed when collisions occur and avoidCollisions is enabled. | |
sideOffset | numberThe distance in pixels from the trigger. | |
sticky | 'partial' | 'always'The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. | |
updatePositionStrategy | 'always' | 'optimized' |
| Emit | Type |
|---|---|
closeAutoFocus | [event: Event] |
dismiss | [] |
entryFocus | [event: Event] |
escapeKeyDown | [event: KeyboardEvent] |
focusOutside | [event: FocusOutsideEvent] |
interactOutside | [event: PointerDownOutsideEvent | FocusOutsideEvent] |
openAutoFocus | [event: Event] |
pointerDownOutside | [event: PointerDownOutsideEvent] |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
| CSS Variable | Description |
|---|---|
--radix-menubar-content-transform-origin |
The transform-origin computed from the content and arrow positions/offsets
|
--radix-menubar-content-available-width |
The remaining width between the trigger and the boundary edge
|
--radix-menubar-content-available-height |
The remaining height between the trigger and the boundary edge
|
--radix-menubar-trigger-width | The width of the trigger |
--radix-menubar-trigger-height | The height of the trigger |
Arrow
An optional arrow element to render alongside a menubar menu. This can be used to help visually link the trigger with the MenubarContent. Must be rendered inside MenubarContent.
| Prop | Default | Type |
|---|---|---|
as | 'svg' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
height | 5 | numberThe height of the arrow in pixels. |
width | 10 | numberThe width of the arrow in pixels. |
Item
The component that contains the menubar items.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Emit | Type |
|---|---|
select | [event: Event] |
| Data Attribute | Value |
|---|---|
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Group
Used to group multiple MenubarItems.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting |
Label
Used to render a label. It won't be focusable using arrow keys.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting |
CheckboxItem
An item that can be controlled and rendered like a checkbox.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
checked | CheckedStateThe controlled checked state of the item. Can be used as | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Emit | Type |
|---|---|
select | [event: Event] |
update:checked | [payload: boolean] |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
RadioGroup
Used to group multiple MenubarRadioItems.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
modelValue | stringThe value of the selected item in the group. |
| Emit | Type |
|---|---|
update:modelValue | [payload: boolean] |
RadioItem
An item that can be controlled and rendered like a radio.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the | |
value* | stringThe unique value of the item. |
| Emit | Type |
|---|---|
select | [event: Event] |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
ItemIndicator
Renders when the parent MenubarCheckboxItem or MenubarRadioItem is checked. You can style this element directly, or you can use it as a wrapper to put an icon into, or both.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. |
| Data Attribute | Value |
|---|---|
[data-state] | "checked" | "unchecked" |
Separator
Used to visually separate items in a menubar menu.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting |
Sub
Contains all the parts of a submenu.
| Prop | Default | Type |
|---|---|---|
defaultOpen | booleanThe open state of the submenu when it is initially rendered. Use when you do not need to control its open state. | |
open | booleanThe controlled open state of the menu. Can be used as |
| Emit | Type |
|---|---|
update:open | [payload: boolean] |
SubTrigger
An item that opens a submenu. Must be rendered inside MenubarSub.
| Prop | Default | Type |
|---|---|---|
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
disabled | booleanWhen | |
textValue | stringOptional text used for typeahead purposes. By default the typeahead behavior will use the |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
SubContent
The component that pops out when a submenu is open. Must be rendered inside MenubarSub.
| Prop | Default | Type |
|---|---|---|
alignOffset | numberAn offset in pixels from the "start" or "end" alignment options. | |
arrowPadding | numberThe padding between the arrow and the edges of the content. If your content has border-radius, this will prevent it from overflowing the corners. | |
as | 'div' | AsTag | ComponentThe element or component this component should render as. Can be overwrite by |
asChild | booleanSetting | |
avoidCollisions | booleanWhen | |
collisionBoundary | Element | (Element | null)[] | nullThe element used as the collision boundary. By default this is the viewport, though you can provide additional element(s) to be included in this check. | |
collisionPadding | number | Partial<Record<'top' | 'right' | 'bottom' | 'left', number>>The distance in pixels from the boundary edges where collision detection should occur. Accepts a number (same for all sides), or a partial padding object, for example: { top: 20, left: 20 }. | |
forceMount | booleanUsed to force mounting when more control is needed. Useful when controlling animation with Vue animation libraries. | |
hideWhenDetached | booleanWhether to hide the content when the trigger becomes fully occluded. | |
loop | booleanWhen | |
sideOffset | numberThe distance in pixels from the trigger. | |
sticky | 'partial' | 'always'The sticky behavior on the align axis. "partial" will keep the content in the boundary as long as the trigger is at least partially in the boundary whilst "always" will keep the content in the boundary regardless. | |
updatePositionStrategy | 'always' | 'optimized' |
| Emit | Type |
|---|---|
closeAutoFocus | [event: Event] |
dismiss | [] |
entryFocus | [event: Event] |
escapeKeyDown | [event: KeyboardEvent] |
focusOutside | [event: FocusOutsideEvent] |
interactOutside | [event: PointerDownOutsideEvent | FocusOutsideEvent] |
openAutoFocus | [event: Event] |
pointerDownOutside | [event: PointerDownOutsideEvent] |
| Data Attribute | Value |
|---|---|
[data-state] | "open" | "closed" |
[data-side] | "left" | "right" | "bottom" | "top" |
[data-align] | "start" | "end" | "center" |
[data-orientation] | "vertical" | "horizontal" |
| CSS Variable | Description |
|---|---|
--radix-menubar-content-transform-origin |
The transform-origin computed from the content and arrow positions/offsets
|
--radix-menubar-content-available-width |
The remaining width between the trigger and the boundary edge
|
--radix-menubar-content-available-height |
The remaining height between the trigger and the boundary edge
|
--radix-menubar-trigger-width | The width of the trigger |
--radix-menubar-trigger-height | The height of the trigger |
Examples
With submenus
You can create submenus by using MenubarSub in combination with its parts.
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarSub,
MenubarSubContent,
MenubarSubTrigger,
MenubarTrigger,
} from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarSub>
<MenubarSubTrigger>Sub menu →</MenubarSubTrigger>
<MenubarPortal>
<MenubarSubContent>
<MenubarItem>Sub menu item</MenubarItem>
<MenubarItem>Sub menu item</MenubarItem>
<MenubarArrow />
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>With disabled items
You can add special styles to disabled items via the data-disabled attribute.
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem class="MenubarItem" disabled>
…
</MenubarItem>
<MenubarItem class="MenubarItem">
…
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarItem[data-disabled] {
color: gainsboro;
}With separators
Use the Separator part to add a separator between items.
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>With labels
Use the Label part to help label a section.
<script setup lang="ts">
import {
MenubarContent,
MenubarItem,
MenubarLabel,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarTrigger,
} from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarLabel>Label</MenubarLabel>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>With checkbox items
Use the CheckboxItem part to add an item that can be checked.
<script setup lang="ts">
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarMenu,
MenubarPortal,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'radix-vue'
import { Icon } from '@iconify/vue'
const checked = ref(true)
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>…</MenubarItem>
<MenubarItem>…</MenubarItem>
<MenubarSeparator />
<MenubarCheckboxItem v-model:checked="checked">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
Checkbox item
</MenubarCheckboxItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>With radio items
Use the RadioGroup and RadioItem parts to add an item that can be checked amongst others.
<script setup lang="ts">
import {
MenubarCheckboxItem,
MenubarContent,
MenubarItem,
MenubarItemIndicator,
MenubarMenu,
MenubarPortal,
MenubarRadioGroup,
MenubarRadioItem,
MenubarRoot,
MenubarSeparator,
MenubarTrigger,
} from 'radix-vue'
import { Icon } from '@iconify/vue'
const color = ref('blue')
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarRadioGroup v-model="color">
<MenubarRadioItem value="red">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
Red
</MenubarRadioItem>
<MenubarRadioItem value="blue">
<MenubarItemIndicator>
<Icon icon="radix-icons:check" />
</MenubarItemIndicator>
Blue
</MenubarRadioItem>
</MenubarRadioGroup>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>With complex items
You can add extra decorative elements in the Item parts, such as images.
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent>
<MenubarItem>
<img src="…">
Adolfo Hess
</MenubarItem>
<MenubarItem>
<img src="…">
Miyah Myles
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>Constrain the content/sub-content size
You may want to constrain the width of the content (or sub-content) so that it matches the trigger (or sub-trigger) width. You may also want to constrain its height to not exceed the viewport.
We expose several CSS custom properties such as --radix-menubar-trigger-width and --radix-menubar-content-available-height to support this. Use them to constrain the content dimensions.
<script setup lang="ts">
import { MenubarContent, MenubarItem, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger> Trigger </MenubarTrigger>
<MenubarPortal>
<MenubarContent class="MenubarContent" :side-offset="5" :align-offset="-3">
<MenubarItem> New Tab </MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
width: var(--radix-menubar-trigger-width);
max-height: var(--radix-menubar-content-available-height);
}Origin-aware animations
We expose a CSS custom property --radix-menubar-content-transform-origin. Use it to animate the content from its computed origin based on side, sideOffset, align, alignOffset and any collisions.
<script setup lang="ts">
import { MenubarContent, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent class="MenubarContent">
…
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
transform-origin: var(--radix-menubar-content-transform-origin);
animation: scaleIn 0.5s ease-out;
}
@keyframes scaleIn {
from {
opacity: 0;
transform: scale(0);
}
to {
opacity: 1;
transform: scale(1);
}
}Collision-aware animations
We expose data-side and data-align attributes. Their values will change at runtime to reflect collisions. Use them to create collision and direction-aware animations.
<script setup lang="ts">
import { MenubarContent, MenubarMenu, MenubarPortal, MenubarRoot, MenubarTrigger } from 'radix-vue'
</script>
<template>
<MenubarRoot>
<MenubarMenu>
<MenubarTrigger>…</MenubarTrigger>
<MenubarPortal>
<MenubarContent class="MenubarContent">
…
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
</MenubarRoot>
</template>/* styles.css */
.MenubarContent {
animation-duration: 0.6s;
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}
.MenubarContent[data-side="top"] {
animation-name: slideUp;
}
.MenubarContent[data-side="bottom"] {
animation-name: slideDown;
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}Accessibility
Adheres to the Menu Button WAI-ARIA design pattern and uses roving tabindex to manage focus movement among menu items.
Keyboard Interactions
| Key | Description |
|---|---|
Space |
When focus is on MenubarTrigger, opens the menubar and focuses the first item.
When focus is on an item, activates the focused item. |
Enter |
When focus is on MenubarTrigger, opens the associated menu.
When focus is on an item, activates the focused item. |
ArrowDown |
When focus is on MenubarTrigger, opens the associated menu.
When focus is on an item, moves focus to the next item. |
ArrowUp | When focus is on an item, moves focus to the previous item. |
ArrowRightArrowLeft |
When focus is on a MenubarTrigger, moves focus to the next or previous item. When focus is on a MenubarSubTrigger, opens or closes the submenu depending on reading direction. When focus is within a MenubarContent, opens the next menu in the menubar
|
Esc |
Closes the currently open menu and moves focus to its MenubarTrigger.
|