Menu
The Menu component presents a structured list of actions, settings, or navigation targets within a transient surface. It supports icons, keyboard shortcuts, hint text, section titles, dividers, and submenu indicators.
import {MenuModule} from "@qualcomm-ui/angular/menu"Examples
Item Customization
Compose the menu to include icons and commands.
import {Component} from "@angular/core"
import {Command, File, FileText, FolderOpen, ImageDown} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {IconDirective} from "@qualcomm-ui/angular/icon"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, ButtonModule, PortalDirective, IconDirective],
providers: [provideIcons({Command, File, FileText, FolderOpen, ImageDown})],
selector: "menu-item-customization-demo",
template: `
<q-menu>
<button emphasis="primary" q-menu-button variant="fill">Show Menu</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">
<div icon="FileText" q-menu-item-start-icon></div>
New Text File
<div q-menu-item-command>
<svg qIcon="Command" size="xs"></svg>
E
</div>
</button>
<button q-menu-item value="new-file">
<div icon="File" q-menu-item-start-icon></div>
New File...
<div q-menu-item-command>
<svg qIcon="Command" size="xs"></svg>
N
</div>
</button>
<button q-menu-item value="open-file">
<div icon="FolderOpen" q-menu-item-start-icon></div>
Open File...
<div q-menu-item-command>
<svg qIcon="Command" size="xs"></svg>
O
</div>
</button>
<button q-menu-item value="export">
<div icon="ImageDown" q-menu-item-start-icon></div>
Export
<div q-menu-item-command>
<svg qIcon="Command" size="xs"></svg>
S
</div>
</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuItemCustomizationDemo {}Menu Button
Use q-menu-button for a labeled trigger and q-menu-icon-button for an icon-only trigger. Both automatically render a chevron indicator. Always provide an aria-label on q-menu-icon-button to give assistive technologies an accessible name. Control the menu position with positioning.placement.
import {Component} from "@angular/core"
import {
Copy,
Ellipsis,
File,
FileText,
FolderOpen,
Pencil,
Trash2,
} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalComponent} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalComponent],
providers: [
provideIcons({Copy, Ellipsis, File, FileText, FolderOpen, Pencil, Trash2}),
],
selector: "menu-button-demo",
template: `
<div class="flex gap-2.5">
<q-menu [positioning]="{placement: 'bottom-end'}">
<button emphasis="primary" q-menu-button startIcon="File">File</button>
<q-portal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">
<div icon="FileText" q-menu-item-start-icon></div>
New Text File
</button>
<button q-menu-item value="new-file">
<div icon="File" q-menu-item-start-icon></div>
New File...
</button>
<button q-menu-item value="open-file">
<div icon="FolderOpen" q-menu-item-start-icon></div>
Open File...
</button>
</div>
</div>
</q-portal>
</q-menu>
<q-menu size="sm">
<button
aria-label="More actions"
emphasis="primary"
icon="Ellipsis"
q-menu-icon-button
></button>
<q-portal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="rename">
<div icon="Pencil" q-menu-item-start-icon></div>
Rename
</button>
<button q-menu-item value="duplicate">
<div icon="Copy" q-menu-item-start-icon></div>
Duplicate
</button>
<button q-menu-item value="delete">
<div icon="Trash2" q-menu-item-start-icon></div>
Delete
</button>
</div>
</div>
</q-portal>
</q-menu>
</div>
`,
})
export class MenuButtonDemo {}Split Button
Use q-menu-split-button for a split button trigger. The icon-only trigger provides a default "More options" aria-label; project a q-menu-icon-button with your own to override it. Optionally add an aria-label on the group when both halves share an accessible name. Control the menu position with positioning.placement on the parent <q-menu>.
import {Component} from "@angular/core"
import {Download, FileArchive, FileJson, FileText} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalDirective],
providers: [provideIcons({Download, FileArchive, FileJson, FileText})],
selector: "menu-split-button-demo",
template: `
<q-menu [positioning]="{placement: 'bottom-end'}">
<div
aria-label="Download"
emphasis="primary"
q-menu-split-button
startIcon="Download"
(actionClicked)="onDownload()"
>
Download
</div>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="pdf">
<div icon="FileText" q-menu-item-start-icon></div>
Download as PDF
</button>
<button q-menu-item value="json">
<div icon="FileJson" q-menu-item-start-icon></div>
Download as JSON
</button>
<button q-menu-item value="zip">
<div icon="FileArchive" q-menu-item-start-icon></div>
Download as ZIP
</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuSplitButtonDemo {
onDownload() {
console.log("Download")
}
}Custom Action Button
To set HTML attributes on the action button (type, form, name, etc.), project a <button q-button>. Listen on its (click) directly as (actionClicked) will be ignored in that case. Group props (density, emphasis, size, variant) still cascade to the projected button via context.
import {Component} from "@angular/core"
import {Copy, FilePlus, Save} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [ButtonModule, MenuModule, PortalDirective],
providers: [provideIcons({Copy, FilePlus, Save})],
selector: "menu-split-button-projection-demo",
template: `
<q-menu [positioning]="{placement: 'bottom-end'}">
<div emphasis="primary" q-menu-split-button size="sm">
<button
form="settings-form"
name="save"
q-button
startIcon="Save"
type="submit"
(click)="onSave($event)"
>
Save
</button>
</div>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="save-as">
<div icon="FilePlus" q-menu-item-start-icon></div>
Save As…
</button>
<button q-menu-item value="save-copy">
<div icon="Copy" q-menu-item-start-icon></div>
Save a Copy
</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuSplitButtonProjectionDemo {
onSave(event: MouseEvent) {
console.log("Save", event)
}
}Context Menu
Demonstrates how to trigger a menu on right-click or other context events.
import {Component} from "@angular/core"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalDirective],
selector: "menu-context-menu-demo",
template: `
<q-menu class="w-full">
<button
class="flex h-48 w-full flex-1 items-center justify-center border border-dashed"
q-menu-context-trigger
>
Right click here
</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuContextMenuDemo {}Nested Menus
Compose nested menus by nesting <Menu.Root> components inside each other.
<q-menu>
<button emphasis="primary" q-menu-button variant="fill">Show Menu</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<q-menu>
<button q-menu-trigger-item value="open-recent">
Open Recents
</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="file-1">File 1</button>
<button q-menu-item value="file-2">File 2</button>
<button q-menu-item value="file-3">File 3</button>
</div>
</div>
</ng-container>
</q-menu>
</div>
</div>
</ng-container>
</q-menu>
Links
Menu items can be links.
<div q-menu-content>
<a
href="https://angular.dev"
q-menu-item
target="_blank"
value="angular-dev"
>
<div icon="ExternalLink" q-menu-item-start-icon></div>
angular.dev
</a>
<a
fragment="links"
q-menu-item
routerLink="/components/menu"
value="menu-links-demo"
>
Menu Links Demo
</a>
</div>
Groups
Use the q-menu-item-group component to group menu items.
Item Types
There are three item types, each corresponding to one of the three types of aria menu item roles:
q-menu-item—menuitemq-menu-radio-item—menuitemradioq-menu-checkbox-item—menuitemcheckbox
Checkbox Items
There are two appearance options:
- For a checkbox appearance, render the
q-menu-checkbox-item-controldirective as a child of the item. - Render the
q-menu-item-indicatorelement for a simple selection indicator.
<div q-menu-item-group>
<label q-menu-item-group-label>Choose an option</label>
<button q-menu-checkbox-item value="item-1-1">
<div q-menu-checkbox-item-control></div>
<div q-menu-item-label>Option 1</div>
</button>
<button q-menu-checkbox-item value="item-1-2">
<div q-menu-checkbox-item-control></div>
<div q-menu-item-label>Option 2</div>
</button>
</div>
<div q-menu-item-group>
<label q-menu-item-group-label>Choose an option</label>
<button q-menu-checkbox-item value="item-2-1">
<div q-menu-item-label>Option 1</div>
<div q-menu-item-indicator></div>
</button>
<button q-menu-checkbox-item value="item-2-2">
<div q-menu-item-label>Option 2</div>
<div q-menu-item-indicator></div>
</button>
</div>
Checkbox Selection State
Illustrates how to manage and reflect the checked state of checkbox menu items. The useCheckboxGroup helper from @qualcomm-ui/angular-core/checkbox manages a group of values; wire each item's checked and (checkedChanged) bindings to it.
<div q-menu-item-group>
<label q-menu-item-group-label>Choose an option</label>
@for (item of items; track item.value) {
<button
q-menu-checkbox-item
[checked]="checkboxGroup.isChecked(item.value)"
[value]="item.value"
(checkedChanged)="checkboxGroup.toggleValue(item.value)"
>
{{ item.label }}
<div q-menu-item-indicator></div>
</button>
}
</div>
Radio Group
Demonstrates how to group radio menu items so only one can be selected at a time.
<div q-menu-radio-item-group>
<label q-menu-item-group-label>Choose an option</label>
<button q-menu-radio-item value="one">
<div q-menu-radio-item-control></div>
<div q-menu-item-label>Option 1</div>
</button>
<button q-menu-radio-item value="two">
<div q-menu-radio-item-control></div>
<div q-menu-item-label>Option 2</div>
</button>
<button q-menu-radio-item value="three">
<div q-menu-radio-item-control></div>
<div q-menu-item-label>Option 3</div>
</button>
</div>
Radio Group State
Radio item state can be controlled via the value input on the parent q-menu-radio-item-group element.
<div q-menu-radio-item-group>
<label q-menu-item-group-label>Choose an option</label>
<div q-menu-radio-item-group [(value)]="value">
<button q-menu-radio-item value="option-1">
Option 1
<div q-menu-item-indicator></div>
</button>
<button q-menu-radio-item value="option-2">
Option 2
<div q-menu-item-indicator></div>
</button>
<button q-menu-radio-item value="option-3">
Option 3
<div q-menu-item-indicator></div>
</button>
</div>
</div>
Controlled State
The menu's visibility can be controlled via the open, openChanged, and defaultOpen properties.
- Use
opento explicitly set whether the menu is open (controlled mode). - Use
openChangedto be notified when the menu requests to open or close. - Use
defaultOpento set the initial open state when you don't need to control it yourself (uncontrolled mode).
In controlled mode, the open prop should be updated in response to openChanged events to reflect the desired visibility.
import {Component, signal} from "@angular/core"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalDirective],
selector: "menu-controlled-state-demo",
template: `
<q-menu [open]="open()" (openChanged)="open.set($event)">
<button emphasis="primary" q-menu-button variant="fill">Show Menu</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuControlledStateDemo {
protected readonly open = signal(false)
}Placement
Configure the menu's placement using the positioning.placement prop.
import {Component} from "@angular/core"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalDirective],
selector: "menu-placement-demo",
template: `
<q-menu [positioning]="{placement: 'right-start'}">
<button emphasis="primary" q-menu-button variant="fill">Show Menu</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuPlacementDemo {}Sizes
Use the size input on q-menu to control the size of the menu. The default size is md.
The q-menu-button and q-menu-icon-button triggers inherit the menu's size, so the trigger and menu match by default. Such a trigger can run larger than its menu: set size on it to override the inherited value. An md menu pairs with an md or lg trigger. A compact trigger should always pair with an sm menu. When a trigger uses density="compact", set size="sm" on q-menu.
Other trigger content does not inherit the menu size. A link, an avatar, or a custom element placed in the trigger must be sized directly.
import {Component} from "@angular/core"
import {LogOut, Settings, User} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalComponent} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalComponent],
providers: [provideIcons({LogOut, Settings, User})],
selector: "menu-sizes-demo",
template: `
<q-menu size="sm">
<button emphasis="primary" q-menu-button>Show Menu</button>
<q-portal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="account">
<div icon="User" q-menu-item-start-icon></div>
Account
</button>
<button q-menu-item value="settings">
<div icon="Settings" q-menu-item-start-icon></div>
Settings
</button>
<button q-menu-item value="logout">
<div icon="LogOut" q-menu-item-start-icon></div>
Logout
</button>
</div>
</div>
</q-portal>
</q-menu>
`,
})
export class MenuSizesDemo {}Anchor Point
Use the positioning.anchorPoint prop to control the anchor point of the menu.
import {Component, computed, type ElementRef, viewChild} from "@angular/core"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
import type {PositioningOptions} from "@qualcomm-ui/dom/floating-ui"
@Component({
imports: [MenuModule, PortalDirective],
selector: "menu-anchor-point-demo",
template: `
<div class="flex flex-col gap-4">
<q-menu [positioning]="positioning()">
<button emphasis="primary" q-menu-button variant="fill">
Show Menu
</button>
<div
#anchorRef
class="font-body-lg text-neutral-primary bg-neutral-04 border-neutral-01 rounded-md border p-4"
>
Anchor
</div>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</ng-container>
</q-menu>
</div>
`,
})
export class MenuAnchorPointDemo {
protected readonly anchorRef =
viewChild.required<ElementRef<HTMLDivElement>>("anchorRef")
protected readonly positioning = computed<PositioningOptions>(() => ({
getAnchorRect: () => this.anchorRef().nativeElement.getBoundingClientRect(),
}))
}Avatar
Here's an example that composes the Menu with the Avatar component to display a user account menu.
import {Component} from "@angular/core"
import {LogOut, Settings, User} from "lucide-angular"
import {provideIcons} from "@qualcomm-ui/angular-core/lucide"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {AvatarModule} from "@qualcomm-ui/angular/avatar"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [AvatarModule, MenuModule, PortalDirective],
providers: [provideIcons({LogOut, Settings, User})],
selector: "menu-avatar-demo",
template: `
<q-menu [positioning]="{placement: 'right-start'}">
<button q-avatar q-menu-trigger status="active">
<img alt="John Doe" q-avatar-image src="/images/avatar-man.png" />
<div q-avatar-content>JD</div>
<div q-avatar-status></div>
</button>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="account">
<div icon="User" q-menu-item-start-icon></div>
Account
</button>
<button q-menu-item value="settings">
<div icon="Settings" q-menu-item-start-icon></div>
Settings
</button>
<button q-menu-item value="logout">
<div icon="LogOut" q-menu-item-start-icon></div>
Logout
</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuAvatarDemo {}Within Dialog
When using the Menu inside a Dialog, don't render the q-menu-positioner within a portal element.
import {Component} from "@angular/core"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {ButtonModule} from "@qualcomm-ui/angular/button"
import {DialogModule} from "@qualcomm-ui/angular/dialog"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, ButtonModule, DialogModule, PortalDirective],
selector: "menu-within-dialog-demo",
template: `
<div q-dialog-root>
<button emphasis="primary" q-button q-dialog-trigger variant="fill">
Show Dialog
</button>
<ng-container *qPortal>
<div q-dialog-backdrop></div>
<div q-dialog-positioner>
<section class="w-72" q-dialog-content>
<div q-dialog-body>
<button q-dialog-close-button></button>
<h3 q-dialog-heading>Dialog Title</h3>
<q-menu>
<button
class="place-self-start"
emphasis="primary"
q-menu-button
variant="fill"
>
Show Menu
</button>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">
New Text File
</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</q-menu>
</div>
</section>
</div>
</ng-container>
</div>
`,
})
export class MenuWithinDialogDemo {}Hide When Detached
Use the positioning.hideWhenDetached prop to hide the menu when it's detached from the trigger.
import {Component, signal} from "@angular/core"
import {IntersectionObserverDirective} from "@qualcomm-ui/angular-core/observers"
import {PortalDirective} from "@qualcomm-ui/angular-core/portal"
import {MenuModule} from "@qualcomm-ui/angular/menu"
@Component({
imports: [MenuModule, PortalDirective, IntersectionObserverDirective],
selector: "menu-hide-when-detached-demo",
template: `
<q-menu [open]="open()" [positioning]="{hideWhenDetached: true}">
<div
class="border-neutral-03 box-border flex max-w-72 gap-2 overflow-x-scroll rounded-md border p-4"
>
@for (item of items; track item) {
<div
class="font-body-md text-neutral-primary border-neutral-01 bg-neutral-04 rounded-md border p-3 whitespace-nowrap"
>
Item {{ item }}
</div>
}
<button
class="whitespace-nowrap"
emphasis="primary"
q-menu-button
variant="fill"
(qIntersectionObserver)="handleIntersection($event)"
>
Show Menu
</button>
</div>
<ng-container *qPortal>
<div q-menu-positioner>
<div q-menu-content>
<button q-menu-item value="new-text-file">New Text File</button>
<button q-menu-item value="new-file">New File...</button>
<button q-menu-item value="open-file">Open File...</button>
<button q-menu-item value="export">Export</button>
</div>
</div>
</ng-container>
</q-menu>
`,
})
export class MenuHideWhenDetachedDemo {
items = [...Array(6).keys()]
readonly open = signal(false)
handleIntersection(entries: IntersectionObserverEntry[]) {
if (entries[0]?.isIntersecting) {
// only open the menu when the button is in view,
// but keep it open after to demonstrate the use case.
this.open.set(true)
}
}
}Explorer
Component Anatomy
Hover to highlight, click to view API
API
<q-menu>
{
x: number
y: number
}
booleanbooleanstringboolean'ltr' | 'rtl'
() =>
| Node
| ShadowRoot
| Document
stringstringbooleanbooleanbooleanbooleanboolean'sm' | 'md'
booleanbooleanbooleanKeyboardEventvoidCustomEvent<{
event?: E
}>
string| CustomEvent<{event?: E}>
| CustomEvent<{event?: E}>
{
href: string
node: HTMLAnchorElement
value: string
}
booleanCustomEvent<{
event?: E
}>
CustomEvent<{
originalIndex: number
originalLayer: HTMLElement
targetIndex: number
targetLayer: HTMLElement
}>
stringq-menu-button
| 'default'
| 'compact'
booleantrue, pointer/focus
events are blocked, and the component is visually dimmed.| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
| 'sm'
| 'md'
| 'lg'
| LucideIconData
| string
<svg q-start-icon icon="..."></svg>
| 'fill'
| 'ghost'
| 'outline'
class'qui-menu__button'q-menu-icon-button
| 'default'
| 'compact'
booleantrue, pointer/focus
events are blocked, and the component is visually dimmed.| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
| LucideIconData
| string
| 'square'
| 'rounded'
| 'sm'
| 'md'
| 'lg'
| 'fill'
| 'ghost'
| 'outline'
q-menu-split-button
stringstring| 'default'
| 'compact'
boolean| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
| LucideIconData
| string
| 'sm'
| 'md'
| 'lg'
| LucideIconData
| string
| 'fill'
| 'ghost'
| 'outline'
MouseEventclass'qui-menu__split-button'data-density| 'default'
| 'compact'
data-disableddata-emphasis| 'neutral'
| 'primary'
| 'danger'
| 'white-persistent'
| 'black-persistent'
| 'inverse'
data-size| 'sm'
| 'md'
| 'lg'
data-split-button-part'root'data-variant| 'fill'
| 'ghost'
| 'outline'
q-menu-trigger
stringdata-menu-part'trigger'data-placement| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
data-state| 'open'
| 'closed'
data-uidstringq-menu-content
stringclass'qui-menu__content'data-from| 'trigger'
| 'context-trigger'
data-menu-part'content'data-placement| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
data-size'sm' | 'md'
data-state| 'open'
| 'closed'
hiddenbooleantabIndex0q-menu-item-group
stringclass'qui-menu-item__group'data-menu-part'item-group'q-menu-item-group-label
class'qui-menu-item__group-label'data-menu-part'item-group-label'data-size'sm' | 'md'
q-menu-item
stringbooleanbooleanstringvoidclass'qui-menu-item__root'data-disableddata-focus-visibledata-highlighteddata-menu-part'item'data-ownedbystringdata-size'sm' | 'md'
data-valuestringdata-valuetextstringtabIndex-1
q-menu-item-label
class'qui-menu-item__label'data-disableddata-highlighteddata-menu-part'item-text'data-size'sm' | 'md'
data-state| 'checked'
| 'unchecked'
q-menu-item-start-icon
| LucideIconData
| string
class'qui-menu-item__start-icon'data-menu-part'start-icon'data-size'sm' | 'md'
q-menu-item-description
class'qui-menu-item__description'data-menu-part'description'data-size'sm' | 'md'
q-menu-item-indicator
class'qui-menu-item__indicator'data-disableddata-highlighteddata-menu-part'item-indicator'data-size'sm' | 'md'
data-state| 'checked'
| 'unchecked'
hiddenbooleanq-menu-separator
class'qui-menu__separator'data-menu-part'separator'q-menu-checkbox-item
stringbooleanbooleanbooleanbooleanstringbooleanvoidclass'qui-menu-item__root'data-disableddata-focus-visibledata-highlighteddata-menu-part'item'data-ownedbystringdata-size'sm' | 'md'
data-state| 'checked'
| 'unchecked'
data-typestringdata-valuestringdata-valuetextstringtabIndex-1
q-menu-checkbox-item-control
class'qui-checkbox__control'data-disableddata-menu-part'item-control'data-state| 'checked'
| 'unchecked'
q-menu-radio-item-control
class'qui-radio__control'data-disableddata-menu-part'item-control'data-state| 'checked'
| 'unchecked'
PositioningOptions
The positioning prop accepts an object with the following shape:
numberstring[data-menu-part=arrow]).() =>
| 'clippingAncestors'
| Element
| Array<Element>
| {
height: number
width: number
x: number
y: number
}
boolean| boolean
| Array<
| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
>
(
element:
| HTMLElement
| VirtualElement,
) => {
height?: number
width?: number
x?: number
y?: number
}
numberboolean| boolean
| {
ancestorResize?: boolean
ancestorScroll?: boolean
animationFrame?: boolean
elementResize?: boolean
layoutShift?: boolean
}
{
crossAxis?: number
mainAxis?: number
}
(
data: ComputePositionReturn,
) => void
(data: {
placed: boolean
}) => void
numberboolean| 'bottom'
| 'bottom-end'
| 'bottom-start'
| 'left'
| 'left-end'
| 'left-start'
| 'right'
| 'right-end'
| 'right-start'
| 'top'
| 'top-end'
| 'top-start'
booleannumberboolean| 'absolute'
| 'fixed'
(data: {
updatePosition: () => Promise<void>
}) => void | Promise<void>