Skip to content
Navigation

Dropdown Menu

Added 14 October 2026

React

Codecomponents/react/dropdown-menu-demo.tsx
import {
    DropdownMenu,
    DropdownMenuCheckboxItem,
    DropdownMenuContent,
    DropdownMenuGroup,
    DropdownMenuItem,
    DropdownMenuLabel,
    DropdownMenuRadioGroup,
    DropdownMenuRadioItem,
    DropdownMenuSeparator,
    DropdownMenuShortcut,
    DropdownMenuSub,
    DropdownMenuSubContent,
    DropdownMenuSubTrigger,
    DropdownMenuTrigger,
} from '@stroeer-labs/design-library/react';
import {GlobeIcon, LogOutIcon, SettingsIcon, UserIcon} from 'lucide-react';

const triggerClasses =
    'inline-flex h-10 items-center justify-center rounded-md border border-border bg-secondary px-4 text-sm font-medium text-secondary-foreground hover:bg-secondary/80';

export function DropdownMenuDemo() {
    return (
        <div className="space-y-6">
            <div className="flex flex-col items-start gap-2">
                <p className="text-xs font-medium text-muted-foreground">Items, label, separator, shortcut, submenu</p>
                <DropdownMenu>
                    <DropdownMenuTrigger className={triggerClasses}>Open menu</DropdownMenuTrigger>
                    <DropdownMenuContent align="start" sideOffset={8} className="min-w-56">
                        <DropdownMenuGroup>
                            {/* Base UI requires GroupLabel inside a Group (unlike the Radix upstream) */}
                            <DropdownMenuLabel>My account</DropdownMenuLabel>
                            <DropdownMenuSeparator />
                            <DropdownMenuItem>
                                <UserIcon />
                                Profile
                                <DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
                            </DropdownMenuItem>
                            <DropdownMenuItem>
                                <SettingsIcon />
                                Settings
                                <DropdownMenuShortcut>⌘,</DropdownMenuShortcut>
                            </DropdownMenuItem>
                            <DropdownMenuItem disabled>Billing (disabled)</DropdownMenuItem>
                        </DropdownMenuGroup>
                        <DropdownMenuSeparator />
                        <DropdownMenuSub>
                            <DropdownMenuSubTrigger>
                                <GlobeIcon />
                                Language
                            </DropdownMenuSubTrigger>
                            <DropdownMenuSubContent>
                                <DropdownMenuItem>English</DropdownMenuItem>
                                <DropdownMenuItem>Deutsch</DropdownMenuItem>
                            </DropdownMenuSubContent>
                        </DropdownMenuSub>
                        <DropdownMenuSeparator />
                        <DropdownMenuItem variant="destructive">
                            <LogOutIcon />
                            Log out
                        </DropdownMenuItem>
                    </DropdownMenuContent>
                </DropdownMenu>
            </div>
            <div className="flex flex-col items-start gap-2">
                <p className="text-xs font-medium text-muted-foreground">Checkbox and radio items</p>
                <DropdownMenu>
                    <DropdownMenuTrigger className={triggerClasses}>View options</DropdownMenuTrigger>
                    <DropdownMenuContent align="start" sideOffset={8} className="min-w-56">
                        <DropdownMenuGroup>
                            <DropdownMenuLabel>Appearance</DropdownMenuLabel>
                            <DropdownMenuCheckboxItem defaultChecked>Status bar</DropdownMenuCheckboxItem>
                            <DropdownMenuCheckboxItem>Activity panel</DropdownMenuCheckboxItem>
                        </DropdownMenuGroup>
                        <DropdownMenuSeparator />
                        <DropdownMenuRadioGroup defaultValue="bottom">
                            <DropdownMenuLabel>Panel position</DropdownMenuLabel>
                            <DropdownMenuRadioItem value="top">Top</DropdownMenuRadioItem>
                            <DropdownMenuRadioItem value="bottom">Bottom</DropdownMenuRadioItem>
                            <DropdownMenuRadioItem value="right">Right</DropdownMenuRadioItem>
                        </DropdownMenuRadioGroup>
                    </DropdownMenuContent>
                </DropdownMenu>
            </div>
        </div>
    );
}

Angular

Codecomponents/angular/dropdown-menu-demo.ts
import {Component, signal} from '@angular/core';
import {NgIcon, provideIcons} from '@ng-icons/core';
import {lucideGlobe, lucideLogOut, lucideSettings, lucideUser} from '@ng-icons/lucide';
import {HlmDropdownMenuImports} from '@stroeer-labs/design-library/angular';

@Component({
    selector: 'dl-dropdown-menu-demo',
    standalone: true,
    imports: [HlmDropdownMenuImports, NgIcon],
    viewProviders: [provideIcons({lucideGlobe, lucideLogOut, lucideSettings, lucideUser})],
    template: `
    <div class="space-y-6">
      <div class="flex flex-col items-start gap-2">
        <p class="text-xs font-medium text-muted-foreground">Items, label, separator, shortcut, submenu</p>
        <button
          type="button"
          [hlmDropdownMenuTrigger]="menu"
          class="inline-flex h-10 items-center justify-center rounded-md border border-border bg-secondary px-4 text-sm font-medium text-secondary-foreground hover:bg-secondary/80"
        >
          Open menu
        </button>
        <ng-template #menu>
          <div hlmDropdownMenu sideOffset="8" class="min-w-56">
            <div hlmDropdownMenuLabel>My account</div>
            <div hlmDropdownMenuSeparator></div>
            <div hlmDropdownMenuGroup>
              <button hlmDropdownMenuItem type="button">
                <ng-icon name="lucideUser" />
                Profile
                <span hlmDropdownMenuShortcut>⇧⌘P</span>
              </button>
              <button hlmDropdownMenuItem type="button">
                <ng-icon name="lucideSettings" />
                Settings
                <span hlmDropdownMenuShortcut>⌘,</span>
              </button>
              <button hlmDropdownMenuItem disabled type="button">Billing (disabled)</button>
            </div>
            <div hlmDropdownMenuSeparator></div>
            <button hlmDropdownMenuItem [hlmDropdownMenuSubTrigger]="languageMenu" type="button">
              <ng-icon name="lucideGlobe" />
              Language
              <hlm-dropdown-menu-item-sub-indicator />
            </button>
            <div hlmDropdownMenuSeparator></div>
            <button hlmDropdownMenuItem variant="destructive" type="button">
              <ng-icon name="lucideLogOut" />
              Log out
            </button>
          </div>
        </ng-template>
        <ng-template #languageMenu>
          <div hlmDropdownMenuSub>
            <button hlmDropdownMenuItem type="button">English</button>
            <button hlmDropdownMenuItem type="button">Deutsch</button>
          </div>
        </ng-template>
      </div>
      <div class="flex flex-col items-start gap-2">
        <p class="text-xs font-medium text-muted-foreground">Checkbox and radio items</p>
        <button
          type="button"
          [hlmDropdownMenuTrigger]="viewOptions"
          class="inline-flex h-10 items-center justify-center rounded-md border border-border bg-secondary px-4 text-sm font-medium text-secondary-foreground hover:bg-secondary/80"
        >
          View options
        </button>
        <ng-template #viewOptions>
          <div hlmDropdownMenu sideOffset="8" class="min-w-56">
            <div hlmDropdownMenuLabel>Appearance</div>
            <button hlmDropdownMenuCheckbox [checked]="statusBar()" (triggered)="statusBar.set(!statusBar())" type="button">
              Status bar
              <hlm-dropdown-menu-checkbox-indicator />
            </button>
            <button hlmDropdownMenuCheckbox [checked]="activityPanel()" (triggered)="activityPanel.set(!activityPanel())" type="button">
              Activity panel
              <hlm-dropdown-menu-checkbox-indicator />
            </button>
            <div hlmDropdownMenuSeparator></div>
            <div hlmDropdownMenuLabel>Panel position</div>
            <div hlmDropdownMenuGroup>
              @for (position of positions; track position) {
                <button hlmDropdownMenuRadio [checked]="panelPosition() === position" (triggered)="panelPosition.set(position)" type="button">
                  {{ position }}
                  <hlm-dropdown-menu-radio-indicator />
                </button>
              }
            </div>
          </div>
        </ng-template>
      </div>
    </div>
  `,
})
export class DropdownMenuDemoComponent {
    protected readonly statusBar = signal(true);
    protected readonly activityPanel = signal(false);
    protected readonly panelPosition = signal('Bottom');
    protected readonly positions = ['Top', 'Bottom', 'Right'];
}