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 '@oku-ui/primitives'
const currentMenu = ref('')
const checkboxOne = ref(false)
const checkboxTwo = ref(false)
const person = ref('pedro')
function handleClick() {
// eslint-disable-next-line no-alert
alert('hello!')
}
</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-mauve12 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-indigo4 data-[state=open]:bg-indigo4"
>
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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
disabled
>
New Incognito Window
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarSub>
<MenubarSubTrigger
class="group text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Email Link
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Messages
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Notes
</MenubarItem>
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarItem
class="group text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 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 value="Edit">
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-mauve12 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-indigo4 data-[state=open]:bg-indigo4"
>
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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-indigo6 m-[5px]" />
<MenubarSub>
<MenubarSubTrigger
class="group text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Search the web…
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find…
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find Next
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Find Previous
</MenubarItem>
</MenubarSubContent>
</MenubarPortal>
</MenubarSub>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Cut
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Copy
</MenubarItem>
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Paste
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
<MenubarMenu value="View">
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-mauve12 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-indigo4 data-[state=open]:bg-indigo4"
>
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-mauve12 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-indigo9 data-[highlighted]:text-indigo1"
>
<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-mauve12 group-data-[highlighted]:text-white group-data-[disabled]:text-mauve8"
>
⌘+B
</div>
</MenubarCheckboxItem>
<MenubarCheckboxItem
v-model="checkboxTwo"
class="text-[13px] leading-none text-mauve12 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-indigo9 data-[highlighted]:text-indigo1"
>
<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-indigo6 m-[5px]" />
<MenubarItem
class="group text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Toggle Fullscreen
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
>
Hide Sidebar
</MenubarItem>
</MenubarContent>
</MenubarPortal>
</MenubarMenu>
<MenubarMenu value="Profiles">
<MenubarTrigger
class="py-2 px-3 outline-none select-none font-semibold leading-none rounded text-mauve12 text-[13px] flex items-center justify-between gap-[2px] data-[highlighted]:bg-indigo4 data-[state=open]:bg-indigo4"
>
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-mauve12 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-indigo9 data-[highlighted]:text-indigo1"
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-mauve12 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-indigo9 data-[highlighted]:text-indigo1"
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-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 data-[disabled]:text-mauve8 data-[disabled]:pointer-events-none"
@click="handleClick"
>
Edit…
</MenubarItem>
<MenubarSeparator class="h-[1px] bg-indigo6 m-[5px]" />
<MenubarItem
class="text-[13px] leading-none text-mauve12 rounded flex items-center h-[25px] px-[10px] relative select-none pl-5 outline-none data-[state=open]:bg-indigo4 data-[state=open]:text-mauve12 data-[highlighted]:bg-gradient-to-br data-[highlighted]:from-indigo9 data-[highlighted]:to-indigo10 data-[highlighted]:text-indigo1 data-[highlighted]:data-[state=open]:text-indigo1 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 add @oku-ui/primitives
Anatomy
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 | string | |
dir | 'ltr' | 'rtl' | |
loop | boolean | |
value | string |
Emit | Payload |
---|---|
update:value | [value: string] |
Menu
A top level menu item, contains a trigger with content combination.
Prop | Default | Type |
---|---|---|
value | string |
Trigger
The button that toggles the content. By default, the MenubarContent
will position itself against the trigger.
Prop | Default | Type |
---|---|---|
as | 'div' | object | AsTag |
disabled | boolean |
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
.
Content
The component that pops out when a menu is open.
Prop | Default | Type |
---|---|---|
forceMount | boolean Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. |
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
.
Item
The component that contains the menubar items.
Data Attribute | Value |
---|---|
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
Group
Used to group multiple MenubarItem
s.
Label
Used to render a label. It won't be focusable using arrow keys.
CheckboxItem
An item that can be controlled and rendered like a checkbox.
Data Attribute | Value |
---|---|
[data-state] | "checked" | "unchecked" |
[data-highlighted] | Present when highlighted |
[data-disabled] | Present when disabled |
RadioGroup
Used to group multiple MenubarRadioItem
s.
RadioItem
An item that can be controlled and rendered like a radio.
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.
Data Attribute | Value |
---|---|
[data-state] | "checked" | "unchecked" |
Separator
Used to visually separate items in a menubar menu.
Sub
Contains all the parts of a submenu.
Prop | Default | Type |
---|---|---|
defaultOpen | false | boolean |
open | boolean |
Emit | Payload |
---|---|
update:open | [open: boolean] |
SubTrigger
An item that opens a submenu. Must be rendered inside MenubarSub
.
Prop | Default | Type |
---|---|---|
disabled | boolean | |
textValue | string |
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 |
---|---|---|
forceMount | boolean Used to force mounting when more control is needed. Useful when controlling animation with React animation libraries. |
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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
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 '@oku-ui/primitives'
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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 '@oku-ui/primitives'
</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 .
|