Menu
Build context menus, action lists, and navigation panels with full keyboard support. Menus group related actions together, making them easy to discover and interact with. They support nested submenus, icons, section headings, and danger variants for destructive actions.
import { CoarMenu, CoarMenuItem, CoarMenuDivider, CoarMenuHeading, CoarSubExpand, CoarSubmenuItem } from '@cocoar/vue-ui';Basic Menu
The simplest menu: a list of clickable items separated by dividers. Individual items can be disabled when an action is not available.
Last clicked: none
<template>
<div>
<CoarMenu>
<CoarMenuItem @clicked="handleClick('New File')">New File</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Open...')">Open...</CoarMenuItem>
<CoarMenuDivider />
<CoarMenuItem @clicked="handleClick('Save')">Save</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Save As...')">Save As...</CoarMenuItem>
<CoarMenuDivider />
<CoarMenuItem :disabled="true">Export (disabled)</CoarMenuItem>
</CoarMenu>
<p style="margin-top: 8px; font-size: 13px; color: var(--coar-text-neutral-secondary);">Last clicked: {{ lastClicked || 'none' }}</p>
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { CoarMenu, CoarMenuItem, CoarMenuDivider } from '@cocoar/vue-ui';
const lastClicked = ref('');
function handleClick(item: string) {
lastClicked.value = item;
}
</script>
With Headings
Use CoarMenuHeading to organize a longer menu into labeled sections. This helps users scan for the action they need without reading every item.
<template>
<CoarMenu>
<CoarMenuHeading>File</CoarMenuHeading>
<CoarMenuItem>New</CoarMenuItem>
<CoarMenuItem>Open</CoarMenuItem>
<CoarMenuItem>Recent</CoarMenuItem>
<CoarMenuDivider />
<CoarMenuHeading>Edit</CoarMenuHeading>
<CoarMenuItem>Cut</CoarMenuItem>
<CoarMenuItem>Copy</CoarMenuItem>
<CoarMenuItem>Paste</CoarMenuItem>
</CoarMenu>
</template>
<script setup lang="ts">
import { CoarMenu, CoarMenuItem, CoarMenuDivider, CoarMenuHeading } from '@cocoar/vue-ui';
</script>
With Icons
Leading icons give each item a visual anchor, making menus faster to scan. Use a trash icon on destructive actions like "Delete" to signal their intent.
<template>
<CoarMenu>
<CoarMenuItem icon="plus">New File</CoarMenuItem>
<CoarMenuItem icon="copy">Duplicate</CoarMenuItem>
<CoarMenuItem icon="clipboard">Paste</CoarMenuItem>
<CoarMenuDivider />
<CoarMenuItem icon="settings">Settings</CoarMenuItem>
<CoarMenuItem icon="trash-2">Delete</CoarMenuItem>
</CoarMenu>
</template>
<script setup lang="ts">
import { CoarMenu, CoarMenuItem, CoarMenuDivider } from '@cocoar/vue-ui';
</script>
Nested Submenus
When a menu item leads to a group of related options, wrap them in CoarSubExpand. Submenus expand inline, keeping the user in context without opening a separate overlay.
<template>
<CoarMenu>
<CoarMenuItem @clicked="handleClick('Dashboard')">Dashboard</CoarMenuItem>
<CoarSubExpand label="Settings">
<CoarMenuItem @clicked="handleClick('Profile')">Profile</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Security')">Security</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Notifications')">Notifications</CoarMenuItem>
</CoarSubExpand>
<CoarSubExpand label="Reports">
<CoarMenuItem @clicked="handleClick('Sales')">Sales</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Traffic')">Traffic</CoarMenuItem>
</CoarSubExpand>
<CoarMenuDivider />
<CoarMenuItem @clicked="handleClick('Logout')">Logout</CoarMenuItem>
</CoarMenu>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { CoarMenu, CoarMenuItem, CoarMenuDivider, CoarSubExpand } from '@cocoar/vue-ui';
const lastClicked = ref('');
function handleClick(item: string) {
lastClicked.value = item;
}
</script>
Flyout Submenus
Use CoarSubmenuItem when the submenu should appear as a floating panel beside the trigger instead of expanding inline. The label prop sets the visible text; child items go in the default slot and render inside the flyout.
<template>
<CoarMenu>
<CoarMenuItem icon="home" @clicked="handleClick('Home')">Home</CoarMenuItem>
<CoarSubmenuItem label="Account" icon="user">
<CoarMenu>
<CoarMenuItem icon="user" @clicked="handleClick('Profile')">Profile</CoarMenuItem>
<CoarMenuItem icon="shield" @clicked="handleClick('Security')">Security</CoarMenuItem>
<CoarMenuItem icon="bell" @clicked="handleClick('Notifications')">Notifications</CoarMenuItem>
</CoarMenu>
</CoarSubmenuItem>
<CoarSubmenuItem label="Reports" icon="chart-bar">
<CoarMenu>
<CoarMenuItem @clicked="handleClick('Sales')">Sales</CoarMenuItem>
<CoarMenuItem @clicked="handleClick('Traffic')">Traffic</CoarMenuItem>
</CoarMenu>
</CoarSubmenuItem>
<CoarMenuDivider />
<CoarMenuItem icon="log-out" @clicked="handleClick('Logout')">Logout</CoarMenuItem>
</CoarMenu>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { CoarMenu, CoarMenuItem, CoarMenuDivider, CoarSubmenuItem } from '@cocoar/vue-ui';
const lastClicked = ref('');
function handleClick(item: string) {
lastClicked.value = item;
}
</script>
Borderless (Sidebar)
Pass the borderless prop when embedding a menu inside a sidebar, panel, or card. This removes the outer border and background so the menu blends into its container.
<template>
<div style="background: var(--coar-background-neutral-secondary); border-radius: 8px; padding: 8px;">
<CoarMenu borderless>
<CoarMenuHeading>Navigation</CoarMenuHeading>
<CoarMenuItem icon="home">Home</CoarMenuItem>
<CoarMenuItem icon="user">Profile</CoarMenuItem>
<CoarMenuItem icon="settings">Settings</CoarMenuItem>
</CoarMenu>
</div>
</template>
<script setup lang="ts">
import { CoarMenu, CoarMenuItem, CoarMenuHeading } from '@cocoar/vue-ui';
</script>
Accessibility
Keyboard Navigation
| Key | Action |
|---|---|
Arrow Up / Arrow Down | Move focus between items |
Enter / Space | Activate focused item |
Escape | Close nested submenus |
Tab | Move focus out of the menu |
API
CoarMenu Props
| Prop | Type | Default | Description |
|---|---|---|---|
borderless | boolean | false | Remove outer border/background |
CoarMenuItem Props
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | undefined | Item label text (alternative to default slot) |
icon | string | undefined | Leading icon name |
disabled | boolean | false | Disable the item |
CoarMenuItem Slots
| Slot | Description |
|---|---|
default | Item label content |
CoarMenuItem Events
| Event | Payload | Description |
|---|---|---|
clicked | MenuItemClickEvent | Emitted when item is clicked |
interface MenuItemClickEvent {
event: MouseEvent;
keepMenuOpen(): void; // Call to prevent auto-close of the menu tree
}