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'];
}