menu

A versatile menu component built on top of Angular CDK Menu for creating dropdown and context menus.

PreviousNext
import { Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideBookOpen,
  lucideChevronDown,
  lucideChevronRight,
  lucideFileText,
  lucideInfo,
  lucideUsers,
} from '@ng-icons/lucide';

import { ZardButtonComponent } from '@/shared/components/button';
import { ZardMenuImports } from '@/shared/components/menu/menu.imports';
import { ZardSeparatorComponent } from '@/shared/components/separator';

@Component({
  selector: 'zard-demo-menu-default',
  imports: [ZardMenuImports, ZardButtonComponent, ZardSeparatorComponent, NgIcon],
  template: `
    <nav class="flex items-center justify-between p-4">
      <div class="flex items-center space-x-6">
        <div class="flex items-center space-x-1">
          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="productsMenu">
              Products
              <ng-icon name="lucideChevronDown" class="ml-1" />
            </button>

            <ng-template #productsMenu>
              <div z-menu-content class="w-48">
                <button type="button" z-menu-item (click)="log('Analytics')">Analytics</button>
                <button type="button" z-menu-item (click)="log('Dashboard')">Dashboard</button>
                <button type="button" z-menu-item (click)="log('Reports')">Reports</button>
                <button type="button" z-menu-item zDisabled (click)="log('Insights')">Insights</button>
              </div>
            </ng-template>
          </div>

          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="solutionsMenu">
              Solutions
              <ng-icon name="lucideChevronDown" class="ml-1" />
            </button>

            <ng-template #solutionsMenu>
              <div z-menu-content class="w-80 p-2">
                <div class="grid gap-1">
                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Startups')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Startups</div>
                    <div class="text-muted-foreground mt-1 text-xs">
                      Get started quickly with our startup-friendly tools
                    </div>
                  </button>

                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Enterprise')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Enterprise</div>
                    <div class="text-muted-foreground mt-1 text-xs">
                      Scale your business with enterprise-grade features
                    </div>
                  </button>

                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Agencies')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Agencies</div>
                    <div class="text-muted-foreground mt-1 text-xs">Manage multiple clients with our agency tools</div>
                  </button>
                </div>
              </div>
            </ng-template>
          </div>

          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="resourcesMenu">
              Resources
              <ng-icon name="lucideChevronDown" />
            </button>

            <ng-template #resourcesMenu>
              <div z-menu-content class="w-56">
                <button type="button" z-menu-item (click)="log('Blog')">
                  <ng-icon name="lucideBookOpen" class="mr-2" />
                  Blog
                </button>

                <button type="button" z-menu-item (click)="log('Documentation')">
                  <ng-icon name="lucideFileText" class="mr-2" />
                  Documentation
                </button>

                <button
                  type="button"
                  z-menu-item
                  z-menu
                  [zMenuTriggerFor]="helpSubmenu"
                  zPlacement="rightTop"
                  class="justify-between"
                >
                  <div class="flex items-center">
                    <ng-icon name="lucideInfo" class="mr-2" />
                    Help & Support
                  </div>
                  <ng-icon name="lucideChevronRight" />
                </button>

                <z-separator class="my-2" />

                <button type="button" z-menu-item (click)="log('Community')">
                  <ng-icon name="lucideUsers" class="mr-2" />
                  Community
                </button>
              </div>
            </ng-template>

            <ng-template #helpSubmenu>
              <div z-menu-content class="w-48">
                <button type="button" z-menu-item (click)="log('Getting Started')">Getting Started</button>
                <button type="button" z-menu-item (click)="log('Tutorials')">Tutorials</button>
                <button type="button" z-menu-item (click)="log('FAQ')">FAQ</button>

                <z-separator class="my-2" />

                <button type="button" z-menu-item (click)="log('Contact Support')">Contact Support</button>
                <button type="button" z-menu-item (click)="log('Live Chat')">Live Chat</button>
              </div>
            </ng-template>
          </div>
        </div>
      </div>
    </nav>
  `,
  viewProviders: [
    provideIcons({
      lucideChevronDown,
      lucideChevronRight,
      lucideBookOpen,
      lucideFileText,
      lucideInfo,
      lucideUsers,
    }),
  ],
})
export class ZardDemoMenuDefaultComponent {
  log(item: string) {
    console.log('Navigate to:', item);
  }
}

Installation

Copy
npx zard-cli@latest add menu

Usage

import { ZardMenuImports } from '@/shared/components/menu/menu.imports';
Copy
<div zardContextMenu [zMenuContent]="menuContent">
  Right click here
</div>
<ng-template #menuContent>
  <div zardMenuItem>Back</div>
  <div zardMenuItem>Forward</div>
  <div zardMenuItem>Reload</div>
</ng-template>
Copy

Examples

default

import { Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import {
  lucideBookOpen,
  lucideChevronDown,
  lucideChevronRight,
  lucideFileText,
  lucideInfo,
  lucideUsers,
} from '@ng-icons/lucide';

import { ZardButtonComponent } from '@/shared/components/button';
import { ZardMenuImports } from '@/shared/components/menu/menu.imports';
import { ZardSeparatorComponent } from '@/shared/components/separator';

@Component({
  selector: 'zard-demo-menu-default',
  imports: [ZardMenuImports, ZardButtonComponent, ZardSeparatorComponent, NgIcon],
  template: `
    <nav class="flex items-center justify-between p-4">
      <div class="flex items-center space-x-6">
        <div class="flex items-center space-x-1">
          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="productsMenu">
              Products
              <ng-icon name="lucideChevronDown" class="ml-1" />
            </button>

            <ng-template #productsMenu>
              <div z-menu-content class="w-48">
                <button type="button" z-menu-item (click)="log('Analytics')">Analytics</button>
                <button type="button" z-menu-item (click)="log('Dashboard')">Dashboard</button>
                <button type="button" z-menu-item (click)="log('Reports')">Reports</button>
                <button type="button" z-menu-item zDisabled (click)="log('Insights')">Insights</button>
              </div>
            </ng-template>
          </div>

          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="solutionsMenu">
              Solutions
              <ng-icon name="lucideChevronDown" class="ml-1" />
            </button>

            <ng-template #solutionsMenu>
              <div z-menu-content class="w-80 p-2">
                <div class="grid gap-1">
                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Startups')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Startups</div>
                    <div class="text-muted-foreground mt-1 text-xs">
                      Get started quickly with our startup-friendly tools
                    </div>
                  </button>

                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Enterprise')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Enterprise</div>
                    <div class="text-muted-foreground mt-1 text-xs">
                      Scale your business with enterprise-grade features
                    </div>
                  </button>

                  <button
                    type="button"
                    z-menu-item
                    (click)="log('For Agencies')"
                    class="flex h-auto flex-col items-start py-3"
                  >
                    <div class="text-sm font-medium">For Agencies</div>
                    <div class="text-muted-foreground mt-1 text-xs">Manage multiple clients with our agency tools</div>
                  </button>
                </div>
              </div>
            </ng-template>
          </div>

          <div class="relative">
            <button type="button" z-button zType="ghost" z-menu zTrigger="hover" [zMenuTriggerFor]="resourcesMenu">
              Resources
              <ng-icon name="lucideChevronDown" />
            </button>

            <ng-template #resourcesMenu>
              <div z-menu-content class="w-56">
                <button type="button" z-menu-item (click)="log('Blog')">
                  <ng-icon name="lucideBookOpen" class="mr-2" />
                  Blog
                </button>

                <button type="button" z-menu-item (click)="log('Documentation')">
                  <ng-icon name="lucideFileText" class="mr-2" />
                  Documentation
                </button>

                <button
                  type="button"
                  z-menu-item
                  z-menu
                  [zMenuTriggerFor]="helpSubmenu"
                  zPlacement="rightTop"
                  class="justify-between"
                >
                  <div class="flex items-center">
                    <ng-icon name="lucideInfo" class="mr-2" />
                    Help & Support
                  </div>
                  <ng-icon name="lucideChevronRight" />
                </button>

                <z-separator class="my-2" />

                <button type="button" z-menu-item (click)="log('Community')">
                  <ng-icon name="lucideUsers" class="mr-2" />
                  Community
                </button>
              </div>
            </ng-template>

            <ng-template #helpSubmenu>
              <div z-menu-content class="w-48">
                <button type="button" z-menu-item (click)="log('Getting Started')">Getting Started</button>
                <button type="button" z-menu-item (click)="log('Tutorials')">Tutorials</button>
                <button type="button" z-menu-item (click)="log('FAQ')">FAQ</button>

                <z-separator class="my-2" />

                <button type="button" z-menu-item (click)="log('Contact Support')">Contact Support</button>
                <button type="button" z-menu-item (click)="log('Live Chat')">Live Chat</button>
              </div>
            </ng-template>
          </div>
        </div>
      </div>
    </nav>
  `,
  viewProviders: [
    provideIcons({
      lucideChevronDown,
      lucideChevronRight,
      lucideBookOpen,
      lucideFileText,
      lucideInfo,
      lucideUsers,
    }),
  ],
})
export class ZardDemoMenuDefaultComponent {
  log(item: string) {
    console.log('Navigate to:', item);
  }
}

context menu

import { ChangeDetectionStrategy, Component } from '@angular/core';

import { NgIcon, provideIcons } from '@ng-icons/core';
import { lucideChevronRight } from '@ng-icons/lucide';

import { ZardMenuImports } from '@/shared/components/menu/menu.imports';
import { ZardSeparatorComponent } from '@/shared/components/separator';

@Component({
  selector: 'z-demo-context-menu',
  imports: [ZardMenuImports, ZardSeparatorComponent, NgIcon],
  template: `
    <div
      z-context-menu
      [zContextMenuTriggerFor]="contextMenu"
      class="flex h-38 w-75 items-center justify-center rounded-md border border-dashed text-sm"
    >
      Right click here
    </div>

    <ng-template #contextMenu>
      <div z-menu-content class="w-48">
        <button type="button" z-menu-item (click)="log('Back')">
          Back
          <z-menu-shortcut>⌘[</z-menu-shortcut>
        </button>
        <button type="button" z-menu-item (click)="log('Forward')" zDisabled>
          Forward
          <z-menu-shortcut>⌘]</z-menu-shortcut>
        </button>
        <button type="button" z-menu-item (click)="log('Reload')">
          Reload
          <z-menu-shortcut>⌘R</z-menu-shortcut>
        </button>
        <button
          type="button"
          z-menu-item
          z-menu
          [zMenuTriggerFor]="moreTools"
          zPlacement="rightTop"
          class="justify-between"
        >
          <div class="flex items-center">More Tools</div>
          <ng-icon name="lucideChevronRight" />
        </button>
        <z-separator class="my-2" />
        <z-menu-label>People</z-menu-label>
        <button type="button" z-menu-item (click)="log('Pedro Duarte')">Pedro Duarte</button>
        <button type="button" z-menu-item (click)="log('Colm Tuite')">Colm Tuite</button>
      </div>
    </ng-template>

    <ng-template #moreTools>
      <div z-menu-content class="w-48">
        <button type="button" z-menu-item (click)="log('Save Page')">Save Page...</button>
        <button type="button" z-menu-item (click)="log('Create Shortcut')">Create Shortcut...</button>
        <button type="button" z-menu-item (click)="log('Name Window')">Name Window...</button>
        <z-separator class="my-2" />
        <button type="button" z-menu-item (click)="log('Developer Tools')">Developer Tools</button>
        <z-separator class="my-2" />
        <button type="button" z-menu-item zType="destructive" (click)="log('Delete')">Delete</button>
      </div>
    </ng-template>
  `,
  changeDetection: ChangeDetectionStrategy.OnPush,
  viewProviders: [provideIcons({ lucideChevronRight })],
})
export class ZardDemoContextMenu {
  log(item: string) {
    console.log('Navigate to:', item);
  }
}

API Reference

z-menu-labelComponent

Label component for grouping menu items.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''
[inset] Adds left padding for alignment boolean false

z-menu-shortcutComponent

Component for displaying keyboard shortcuts in menu items.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-menuComponent

The trigger directive that opens the menu when interacted with.

PropertyDescriptionTypeDefault
[zMenuTriggerFor] Reference to the menu template TemplateRef<void> required
[zDisabled] Whether the trigger is disabled boolean false
[zTrigger] How the menu is triggered 'click' | 'hover' 'click'
[zHoverDelay] Delay in ms before closing on hover exit number 100
[zPlacement] Menu position relative to trigger ZardMenuPlacement 'bottomLeft'

z-context-menuComponent

The trigger directive that opens context menu.

PropertyDescriptionTypeDefault
[zContextMenuTriggerFor] Reference to the context menu content TemplateRef<void> required

z-menu-contentComponent

Container directive for menu items.

PropertyDescriptionTypeDefault
[class] Additional CSS classes ClassValue ''

z-menu-itemComponent

Individual menu item directive.

PropertyDescriptionTypeDefault
[zDisabled] Whether the item is disabled boolean false
[zInset] Add left padding for alignment boolean false
[class] Additional CSS classes ClassValue ''
[menuItemTriggered] Emits when item is clicked EventEmitter
github iconwhatsapp icondiscord iconX icon

Made with in Brazil. Open source and available on GitHub .