Menubar
Overview
The manubar is a horizontal navigation bar that provides persistent access to application menus. Menubars organize commands into logical categories like File, Edit, and View, helping users discover and execute application features through keyboard or mouse interaction.
app.ts
import {AfterViewInit, Component, signal, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App implements AfterViewInit { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu'); rendered = signal(false); ngAfterViewInit() { setTimeout(() => { debugger; }, 500); }}
app.html
<div ngMenuBar> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { margin: 0; width: 15rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem; border-radius: 0.25rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--border-color); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="material-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { gap: 3px; width: 15rem; display: flex; flex-direction: column; padding: 0.25rem; border-radius: 1rem; background-color: var(--page-background); box-shadow: 0 1px 2px 1px color-mix(in srgb, var(--primary-contrast) 25%, transparent);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.75rem; font-size: 0.875rem; border-radius: 0.75rem;}[ngMenuItem][data-active='true'] { color: color-mix(in srgb, var(--vivid-pink) 70%, var(--primary-contrast)); background: color-mix(in srgb, var(--vivid-pink) 5%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--gray-500); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="retro-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-size: 0.8rem; --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background)); font-family: 'Press Start 2P'; --retro-button-color: var(--vivid-pink); --retro-shadow-light: color-mix(in srgb, #fff 20%, transparent); --retro-shadow-dark: color-mix(in srgb, #000 20%, transparent); --retro-elevated-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-flat-shadow: 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-clickable-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700); --retro-pressed-shadow: inset 4px 4px 0px 0px var(--retro-shadow-dark), inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu] { margin-top: 8px; width: 15rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 4px dashed var(--vivid-pink); outline-offset: -4px;}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 4px solid #000; margin: 0.25rem 0; opacity: 0.25;}
Usage
Menubars work well for organizing application commands into persistent, discoverable navigation.
Use menubars when:
- Building application command bars (such as File, Edit, View, Insert, Format)
- Creating persistent navigation that stays visible across the interface
- Organizing commands into logical top-level categories
- Need horizontal menu navigation with keyboard support
- Building desktop-style application interfaces
Avoid menubars when:
- Building dropdown menus for individual actions (use Menu with trigger instead)
- Creating context menus (use Menu guide pattern)
- Simple standalone action lists (use Menu instead)
- Mobile interfaces where horizontal space is limited
- Navigation belongs in a sidebar or header navigation pattern
Features
- Horizontal navigation - Left/Right arrow keys move between top-level categories
- Persistent visibility - Always visible, not modal or dismissable
- Hover-to-open - Submenus open on hover after first keyboard or click interaction
- Nested submenus - Support multiple levels of menu depth
- Keyboard navigation - Arrow keys, Enter/Space, Escape, and typeahead search
- Disabled states - Disable entire menubar or individual items
- RTL support - Automatic right-to-left language navigation
Examples
Basic menubar
A menubar provides persistent access to application commands organized into top-level categories. Users navigate between categories with Left/Right arrows and open menus with Enter or Down arrow.
app.ts
import {AfterViewInit, Component, signal, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App implements AfterViewInit { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu'); rendered = signal(false); ngAfterViewInit() { setTimeout(() => { debugger; }, 500); }}
app.html
<div ngMenuBar> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { margin: 0; width: 15rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem; border-radius: 0.25rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--border-color); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="material-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { gap: 3px; width: 15rem; display: flex; flex-direction: column; padding: 0.25rem; border-radius: 1rem; background-color: var(--page-background); box-shadow: 0 1px 2px 1px color-mix(in srgb, var(--primary-contrast) 25%, transparent);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.75rem; font-size: 0.875rem; border-radius: 0.75rem;}[ngMenuItem][data-active='true'] { color: color-mix(in srgb, var(--vivid-pink) 70%, var(--primary-contrast)); background: color-mix(in srgb, var(--vivid-pink) 5%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--gray-500); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="retro-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-size: 0.8rem; --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background)); font-family: 'Press Start 2P'; --retro-button-color: var(--vivid-pink); --retro-shadow-light: color-mix(in srgb, #fff 20%, transparent); --retro-shadow-dark: color-mix(in srgb, #000 20%, transparent); --retro-elevated-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-flat-shadow: 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-clickable-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700); --retro-pressed-shadow: inset 4px 4px 0px 0px var(--retro-shadow-dark), inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu] { margin-top: 8px; width: 15rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 4px dashed var(--vivid-pink); outline-offset: -4px;}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 4px solid #000; margin: 0.25rem 0; opacity: 0.25;}
Press Right arrow to move between File, Edit, and View. Press Enter or Down arrow to open a menu and navigate submenu items with Up/Down arrows.
Disabled menubar items
Disable specific menu items or the entire menubar to prevent interaction. Control whether disabled items can receive keyboard focus with the softDisabled input.
app.ts
import {AfterViewInit, Component, signal, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App implements AfterViewInit { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu'); rendered = signal(false); ngAfterViewInit() { setTimeout(() => { debugger; }, 500); }}
app.html
<div ngMenuBar> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { margin: 0; width: 15rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem; border-radius: 0.25rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--border-color); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="material-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { gap: 3px; width: 15rem; display: flex; flex-direction: column; padding: 0.25rem; border-radius: 1rem; background-color: var(--page-background); box-shadow: 0 1px 2px 1px color-mix(in srgb, var(--primary-contrast) 25%, transparent);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.75rem; font-size: 0.875rem; border-radius: 0.75rem;}[ngMenuItem][data-active='true'] { color: color-mix(in srgb, var(--vivid-pink) 70%, var(--primary-contrast)); background: color-mix(in srgb, var(--vivid-pink) 5%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--gray-500); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="retro-menubar"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: 6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-size: 0.8rem; --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background)); font-family: 'Press Start 2P'; --retro-button-color: var(--vivid-pink); --retro-shadow-light: color-mix(in srgb, #fff 20%, transparent); --retro-shadow-dark: color-mix(in srgb, #000 20%, transparent); --retro-elevated-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-flat-shadow: 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-clickable-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700); --retro-pressed-shadow: inset 4px 4px 0px 0px var(--retro-shadow-dark), inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu] { margin-top: 8px; width: 15rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 4px dashed var(--vivid-pink); outline-offset: -4px;}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 4px solid #000; margin: 0.25rem 0; opacity: 0.25;}
When [softDisabled]="true" on the menubar, disabled items can receive focus but cannot be activated. When [softDisabled]="false", disabled items are skipped during keyboard navigation.
RTL support
Menubars automatically adapt to right-to-left (RTL) languages. Arrow key navigation reverses direction, and submenus position on the left side.
app.ts
import {AfterViewInit, Component, signal, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';import {Dir} from '@angular/cdk/bidi';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [Dir, MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App implements AfterViewInit { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu'); rendered = signal(false); ngAfterViewInit() { setTimeout(() => { debugger; }, 500); }}
app.html
<div ngMenuBar dir="rtl"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_right</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { margin: 0; width: 15rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem; border-radius: 0.25rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--border-color); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';import {Dir} from '@angular/cdk/bidi';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [Dir, MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="material-menubar" dir="rtl"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -6}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-family: var(--inter-font); --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background));}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; border-radius: 0.5rem; border: 1px solid var(--border-color); background-color: var(--page-background);}[ngMenu] { gap: 3px; width: 15rem; display: flex; flex-direction: column; padding: 0.25rem; border-radius: 1rem; background-color: var(--page-background); box-shadow: 0 1px 2px 1px color-mix(in srgb, var(--primary-contrast) 25%, transparent);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.75rem; font-size: 0.875rem; border-radius: 0.75rem;}[ngMenuItem][data-active='true'] { color: color-mix(in srgb, var(--vivid-pink) 70%, var(--primary-contrast)); background: color-mix(in srgb, var(--vivid-pink) 5%, transparent);}[ngMenuItem]:focus { outline: 2px solid var(--vivid-pink);}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 1px solid var(--gray-500); margin: 0.25rem 0; opacity: 0.25;}
app.ts
import {Component, viewChild} from '@angular/core';import {MenuBar, Menu, MenuContent, MenuItem} from '@angular/aria/menu';import {OverlayModule} from '@angular/cdk/overlay';import {Dir} from '@angular/cdk/bidi';@Component({ selector: 'app-root', templateUrl: 'app.html', styleUrl: 'app.css', imports: [Dir, MenuBar, Menu, MenuContent, MenuItem, OverlayModule], standalone: true,})export class App { fileMenu = viewChild<Menu<string>>('fileMenu'); shareMenu = viewChild<Menu<string>>('shareMenu'); editMenu = viewChild<Menu<string>>('editMenu'); viewMenu = viewChild<Menu<string>>('viewMenu'); insertMenu = viewChild<Menu<string>>('insertMenu'); imageMenu = viewChild<Menu<string>>('imageMenu'); chartMenu = viewChild<Menu<string>>('chartMenu'); formatMenu = viewChild<Menu<string>>('formatMenu'); textMenu = viewChild<Menu<string>>('textMenu'); sizeMenu = viewChild<Menu<string>>('sizeMenu'); paragraphMenu = viewChild<Menu<string>>('paragraphMenu'); alignMenu = viewChild<Menu<string>>('alignMenu');}
app.html
<div ngMenuBar class="retro-menubar" dir="rtl"> <div ngMenuItem #fileEl #fileItem="ngMenuItem" class="menu-bar-item" value="File" [submenu]="fileMenu()" > File </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: fileEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #fileMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="New"> <span class="icon material-symbols-outlined">article</span> <span class="label">New</span> <span class="shortcut">⌘N</span> </div> <div ngMenuItem value="Open"> <span class="icon material-symbols-outlined">folder</span> <span class="label">Open</span> <span class="shortcut">⌘O</span> </div> <div ngMenuItem value="Make a copy"> <span class="icon material-symbols-outlined">file_copy</span> <span class="label">Make a copy</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #shareEl value="Share" [submenu]="shareMenu()"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!fileItem.expanded()" [cdkConnectedOverlay]="{origin: shareEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #shareMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Share with others"> <span class="icon material-symbols-outlined">person_add</span> <span class="label">Share with others</span> </div> <div ngMenuItem value="Publish to web"> <span class="icon material-symbols-outlined">public</span> <span class="label">Publish to web</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Download"> <span class="icon material-symbols-outlined">download</span> <span class="label">Download</span> </div> <div ngMenuItem value="Print"> <span class="icon material-symbols-outlined">print</span> <span class="label">Print</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Rename"> <span class="icon material-symbols-outlined">edit</span> <span class="label">Rename</span> </div> <div ngMenuItem value="Delete"> <span class="icon material-symbols-outlined">delete</span> <span class="label">Move to trash</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #editEl #editItem="ngMenuItem" class="menu-bar-item" value="Edit" [submenu]="editMenu()" > Edit </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: editEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #editMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Undo"> <span class="icon material-symbols-outlined">undo</span> <span class="label">Undo</span> <span class="shortcut">⌘Z</span> </div> <div ngMenuItem value="Redo"> <span class="icon material-symbols-outlined">redo</span> <span class="label">Redo</span> <span class="shortcut">⌘Y</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Cut"> <span class="icon material-symbols-outlined">content_cut</span> <span class="label">Cut</span> <span class="shortcut">⌘X</span> </div> <div ngMenuItem value="Copy"> <span class="icon material-symbols-outlined">content_copy</span> <span class="label">Copy</span> <span class="shortcut">⌘C</span> </div> <div ngMenuItem value="Paste"> <span class="icon material-symbols-outlined">content_paste</span> <span class="label">Paste</span> <span class="shortcut">⌘V</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Find and replace"> <span class="icon material-symbols-outlined">find_replace</span> <span class="label">Find and replace</span> <span class="shortcut">⇧⌘H</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #viewEl #viewItem="ngMenuItem" class="menu-bar-item" value="View" [submenu]="viewMenu()" > View </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: viewEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #viewMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Show print layout" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show print layout</span> </div> <div ngMenuItem value="Show ruler" [disabled]="true"> <span class="icon material-symbols-outlined">check</span> <span class="label">Show ruler</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Zoom in"> <span class="label">Zoom in</span> <span class="shortcut">⌘+</span> </div> <div ngMenuItem value="Zoom out"> <span class="label">Zoom out</span> <span class="shortcut">⌘-</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem value="Full screen"> <span class="label">Full screen</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #insertEl #insertItem="ngMenuItem" class="menu-bar-item" value="Insert" [submenu]="insertMenu()" > Insert </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: insertEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #insertMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #imageEl value="Image" [submenu]="imageMenu()"> <span class="icon material-symbols-outlined">image</span> <span class="label">Image</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: imageEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #imageMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Upload from computer"> <span class="icon material-symbols-outlined">upload</span> <span class="label">Upload from computer</span> </div> <div ngMenuItem value="Search the web"> <span class="icon material-symbols-outlined">search</span> <span class="label">Search the web</span> </div> <div ngMenuItem value="By URL"> <span class="icon material-symbols-outlined">link</span> <span class="label">By URL</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Table"> <span class="icon material-symbols-outlined">table_chart</span> <span class="label">Table</span> </div> <div ngMenuItem #chartEl value="Chart" [submenu]="chartMenu()"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Chart</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!insertItem.expanded()" [cdkConnectedOverlay]="{origin: chartEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #chartMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bar"> <span class="icon material-symbols-outlined">bar_chart</span> <span class="label">Bar</span> </div> <div ngMenuItem value="Column"> <span class="icon material-symbols-outlined">insert_chart</span> <span class="label">Column</span> </div> <div ngMenuItem value="Line"> <span class="icon material-symbols-outlined">show_chart</span> <span class="label">Line</span> </div> <div ngMenuItem value="Pie"> <span class="icon material-symbols-outlined">pie_chart</span> <span class="label">Pie</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem value="Horizontal line"> <span class="icon material-symbols-outlined">horizontal_rule</span> <span class="label">Horizontal line</span> </div> </ng-template> </div> </ng-template> <div ngMenuItem #formatEl #formatItem="ngMenuItem" class="menu-bar-item" value="Format" [submenu]="formatMenu()" > Format </div> <ng-template [cdkConnectedOverlayOpen]="true" [cdkConnectedOverlay]="{origin: formatEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'start', originY: 'bottom', overlayX: 'start', overlayY: 'top', offsetY: 4}]" cdkAttachPopoverAsChild > <div ngMenu #formatMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem #textEl #textItem="ngMenuItem" value="Text" [submenu]="textMenu()"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Text</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: textEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #textMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Bold"> <span class="icon material-symbols-outlined">format_bold</span> <span class="label">Bold</span> <span class="shortcut">⌘B</span> </div> <div ngMenuItem value="Italic"> <span class="icon material-symbols-outlined">format_italic</span> <span class="label">Italic</span> <span class="shortcut">⌘I</span> </div> <div ngMenuItem value="Underline"> <span class="icon material-symbols-outlined">format_underlined</span> <span class="label">Underline</span> <span class="shortcut">⌘U</span> </div> <div ngMenuItem value="Strikethrough"> <span class="icon material-symbols-outlined">strikethrough_s</span> <span class="label">Strikethrough</span> <span class="shortcut">⇧⌘X</span> </div> <div role="separator" class="example-menu-item-separator"></div> <div ngMenuItem #sizeEl value="Size" [submenu]="sizeMenu()"> <span class="label">Size</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!textItem.expanded()" [cdkConnectedOverlay]="{origin: sizeEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #sizeMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Increase font size"> <span class="label">Increase font size</span> <span class="shortcut">⇧⌘.</span> </div> <div ngMenuItem value="Decrease font size"> <span class="label">Decrease font size</span> <span class="shortcut">⇧⌘,</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template> <div ngMenuItem #paragraphEl value="Paragraph styles" [submenu]="paragraphMenu()"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Paragraph styles</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: paragraphEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #paragraphMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Normal text">Normal text</div> <div ngMenuItem value="Heading 1">Heading 1</div> <div ngMenuItem value="Heading 2">Heading 2</div> </ng-template> </div> </ng-template> <div ngMenuItem #alignEl [submenu]="alignMenu()" value="Align & indent"> <span class="icon material-symbols-outlined">format_indent_increase</span> <span class="label">Align & indent</span> <span class="icon arrow material-symbols-outlined">arrow_left</span> </div> <ng-template [cdkConnectedOverlayOpen]="!!formatItem.expanded()" [cdkConnectedOverlay]="{origin: alignEl, usePopover: 'inline'}" [cdkConnectedOverlayPositions]="[{originX: 'end', originY: 'top', overlayY: 'top', overlayX: 'start', offsetX: -12}]" cdkAttachPopoverAsChild > <div ngMenu #alignMenu="ngMenu"> <ng-template ngMenuContent> <div ngMenuItem value="Align left"> <span class="icon material-symbols-outlined">format_align_left</span> <span class="label">Align left</span> </div> <div ngMenuItem value="Align center"> <span class="icon material-symbols-outlined">format_align_center</span> <span class="label">Align center</span> </div> <div ngMenuItem value="Align right"> <span class="icon material-symbols-outlined">format_align_right</span> <span class="label">Align right</span> </div> <div ngMenuItem value="Justify"> <span class="icon material-symbols-outlined">format_align_justify</span> <span class="label">Justify</span> </div> </ng-template> </div> </ng-template> </ng-template> </div> </ng-template></div>
app.css
@import url('https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap');@import url('https://fonts.googleapis.com/icon?family=Material+Symbols+Outlined');:host { display: flex; justify-content: center; font-size: 0.8rem; --border-color: color-mix(in srgb, var(--full-contrast) 20%, var(--page-background)); font-family: 'Press Start 2P'; --retro-button-color: var(--vivid-pink); --retro-shadow-light: color-mix(in srgb, #fff 20%, transparent); --retro-shadow-dark: color-mix(in srgb, #000 20%, transparent); --retro-elevated-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-flat-shadow: 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700); --retro-clickable-shadow: inset 4px 4px 0px 0px var(--retro-shadow-light), inset -4px -4px 0px 0px var(--retro-shadow-dark), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 8px 8px 0px 0px var(--gray-700); --retro-pressed-shadow: inset 4px 4px 0px 0px var(--retro-shadow-dark), inset -4px -4px 0px 0px var(--retro-shadow-light), 4px 0px 0px 0px var(--gray-700), 0px 4px 0px 0px var(--gray-700), -4px 0px 0px 0px var(--gray-700), 0px -4px 0px 0px var(--gray-700), 0px 0px 0px 0px var(--gray-700);}[ngMenuBar] { display: flex; gap: 0.25rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu] { margin-top: 8px; width: 15rem; padding: 0.25rem; background-color: var(--page-background); box-shadow: var(--retro-flat-shadow);}[ngMenu][data-visible='false'] { display: none;}[ngMenuItem] { outline: none; display: flex; cursor: pointer; align-items: center; gap: 0.5rem; padding: 0.5rem; font-size: 0.875rem;}[ngMenuItem][data-active='true'] { background: color-mix(in srgb, var(--border-color) 10%, transparent);}[ngMenuItem]:focus { outline: 4px dashed var(--vivid-pink); outline-offset: -4px;}[ngMenuItem] .icon { opacity: 0.875; font-size: 1.25rem;}[ngMenuItem] .label { flex: 1; opacity: 0.875; font-size: 0.875rem;}[ngMenuItem]:not([aria-expanded='true']) .arrow { opacity: 0.5;}[ngMenu] .separator { border-top: 4px solid #000; margin: 0.25rem 0; opacity: 0.25;}
The dir="rtl" attribute enables RTL mode. Left arrow moves right, Right arrow moves left, maintaining natural navigation for RTL language users.
APIs
The menubar pattern uses directives from Angular's Aria library. See the Menu guide for complete API documentation.
MenuBar
The horizontal container for top-level menu items.
Inputs
| Property | Type | Default | Description |
|---|---|---|---|
disabled |
boolean |
false |
Disables the entire menubar |
wrap |
boolean |
true |
Whether keyboard navigation wraps from last to first item |
softDisabled |
boolean |
true |
When true, disabled items are focusable but not interactive |
See the Menu API documentation for complete details on all available inputs and signals.
MenuItem
Individual items within the menubar. Same API as Menu - see MenuItem.
Menubar-specific behavior:
- Left/Right arrows navigate between menubar items (vs Up/Down in vertical menus)
- First keyboard interaction or click enables hover-to-open for submenus
- Enter or Down arrow opens the submenu and focuses the first item
aria-haspopup="menu"indicates items with submenus
MenuTrigger
Not typically used in menubars - MenuItem handles trigger behavior directly when it has an associated submenu. See MenuTrigger for standalone menu trigger patterns.