`)
- **Tab order:** Users can go to the next and previous items with `Tab` and `Shift+Tab`. When they have opened a sub-menu, the next focusable element is inside the sub-menu. When they have closed it, the focus jumps back to where it was.
- **Dismissal:** Users can close a menu or sub-menu with `ESC`
- **Arrow keys:** Users can move up and down a menu, open sub-menus with `->` and close them with `<-`. I have added something like this to `Tabs.vue`, for reference.
### Implement expected behavior
> Switching to submenus is error-prone. When moving cursor into freshly opened submenu, it should not close if the cursor crosses another menu item.
- **Dead triangle:** Add a triangular invisible node that covers the possible paths from the current mouse position to the menu items.
---
> Large menus disappear. I can't scroll to see all options.
- **Submenu-to-Modal:** Lists longer than 12 or so items are not recommended and should be replaced with modals.
---
> Submenus open without a delay, and they don't close unless I click somewhere outside them, which goes against established expectations.
- **Expansion delay:** Sub-menus open after 200ms
- **Auto-close:** Sub-menus close when the outside is hovered. There may be a delay of 200ms. Menus close when they lose focus.
---
Common UI libraries in the Vue ecosystem such as vuetify or shadcn-vue all implement these features. It may be prudent to use their components.
::: tip Quick mitigation tactics:
- Place complex interfaces into nested [`Modal`](./modal)s
- Place long lists into [native `
` elements](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/select)
- Avoid sub-menus
:::
Common uses:
- "More actions" dropdown menus
- Navigation menus
- Settings menus
- Context menus (right-click menus)
| Prop | Data type | Required? | Description |
| ------ | --------- | --------- | ---------------------------------------------------------- |
| `open` | Boolean | No | Controls whether the popover is open. Defaults to `false`. |
[[toc]]
```vue-html
```
Destructure the function `toggleOpen` and let
a [default dropdown button: `OptionsButton`](./button/options.md) trigger it. This way, the state of the component is encapsulated.
## Bind to `isOpen`
If you want to process or influence the expansion of the menu in the containing component, you can bind it to a `ref`.
Use [Vue event handling](https://vuejs.org/guide/essentials/event-handling.html) to map the button to a boolean value.
```vue{7}
```
## Customize the dropdown button
```vue
{
console.log('Pill clicked');
console.log('Before toggleOpen:', isOpen);
toggleOpen();
console.log('After toggleOpen:', isOpen);
}
"
:blue="bcPrivacy === 'pod'"
:red="bcPrivacy === 'public'"
>
{{ bcPrivacy }}
```
{
console.log('Pill clicked');
console.log('Before toggleOpen:', isOpen);
toggleOpen();
console.log('After toggleOpen:', isOpen);
}"
:blue="bcPrivacy === 'pod'"
:red="bcPrivacy === 'public'"
>
{{ bcPrivacy }}
## Items
Popovers contain a list of menu items. Items can contain different information based on their type.
::: info
Lists of items must be nested inside a `` tag directly under the `` tag.
:::
### Popover item
The popover item (`PopoverItem`) is a simple button that uses [Vue event handling](https://vuejs.org/guide/essentials/event-handling.html). Each item contains a [slot](https://vuejs.org/guide/components/slots.html) which you can use to add a menu label and icon.
```vue{10-13}
Report
```
Report
### Checkbox
The checkbox (`PopoverCheckbox`) is an item that acts as a selectable box. Use [`v-model`](https://vuejs.org/api/built-in-directives.html#v-model) to bind the checkbox to a boolean value. Each checkbox contains a [slot](https://vuejs.org/guide/components/slots.html) which you can use to add a menu label.
```vue{11-16}
Bandcamp
Creative commons
```
Bandcamp
Creative commons
### Radio
The radio (`PopoverRadio`) is an item that acts as a radio selector.
| Prop | Data type | Required? | Description |
| ------------ | --------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `modelValue` | String | Yes | The current value of the radio. Use [`v-model`](https://vuejs.org/api/built-in-directives.html#v-model) to bind this to a value. |
| `choices` | Array\ | Yes | A list of choices. |
```vue
```
### Separator
Use a standard horizontal rule (` `) to add visual separators to popover lists.
```vue{14}
Bandcamp
Creative commons
```
Bandcamp
Creative commons
### Icon Prop
PopoverItem supports an `icon` prop to easily add icons to menu items. The icon prop accepts standard Bootstrap icon classes.
| Prop | Data type | Required? | Description |
| ------ | --------- | --------- | ----------------------------------------------- |
| `icon` | String | No | Bootstrap icon class to display before the item |
```vue-html
Play next
Share
```
Play next
Share
```
## Submenus
To create more complex menus, you can use submenus (`PopoverSubmenu`). Submenus are menu items which contain other menu items.
```vue{10-18}
Organize and share
Bandcamp
```
Organize and share
Bandcamp
## Extra items
You can add extra items to the right hand side of a popover item by nesting them in a `` tag. Use this to add additional menus or buttons to menu items.
```vue{18-29,34-37}
Organize and share
Bandcamp
{{ bcPrivacy }}
Share by link
```
Organize and share
Bandcamp
{{ bcPrivacy }}
Share by link
## Links
You can use `PopoverItem`s as Links by providing a `to` prop with the route object or and external Url (`http...`). Read more on the [Link component](./link) page.
Hello
Change language
{{ language }}
## Menu
Here is an example of a completed menu containing all supported features.
```vue
Change language
{{ language }}
Play next
Append to queue
Add to playlist
Sample playlist
New playlist
Add to favorites
Organize and share
Bandcamp
{{ bcPrivacy }}
Creative Commons
{{ ccPrivacy }}
New library
Share by link
Download
Report
```
Play next
Append to queue
Change language
{{ language }}
Add to playlist
Sample playlist
New playlist
Add to favorites
Organize and share
Bandcamp
{{ bcPrivacy }}
Creative Commons
{{ ccPrivacy }}
New library
Share by link
Download
Report