ComponentsFeedback
Dropdown Menu
Displays a menu of actions or options triggered by a button click
The DropdownMenu component displays a list of actions or options when users click a trigger element. Built on Radix UI DropdownMenu, it handles positioning, keyboard navigation, focus management, checkbox/radio items, and sub-menus automatically.
Import
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuSeparator,
DropdownMenuLabel,
DropdownMenuCheckboxItem,
DropdownMenuRadioGroup,
DropdownMenuRadioItem,
DropdownMenuSub,
DropdownMenuSubTrigger,
DropdownMenuSubContent,
} from '@nim-ui/components';Basic Usage
Code
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Open Menu</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuLabel>My Account</DropdownMenuLabel>
<DropdownMenuSeparator />
<DropdownMenuItem>Profile</DropdownMenuItem>
<DropdownMenuItem>Settings</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem>Log out</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Variants
Two visual styles: default (subtle border) and outline (thicker border).
Code
<DropdownMenuContent variant="default">...</DropdownMenuContent>
<DropdownMenuContent variant="outline">...</DropdownMenuContent>Checkbox Items
Use DropdownMenuCheckboxItem for togglable options within the menu.
Code
const [showToolbar, setShowToolbar] = useState(true);
const [showSidebar, setShowSidebar] = useState(false);
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">View Options</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuCheckboxItem checked={showToolbar} onCheckedChange={setShowToolbar}>
Show Toolbar
</DropdownMenuCheckboxItem>
<DropdownMenuCheckboxItem checked={showSidebar} onCheckedChange={setShowSidebar}>
Show Sidebar
</DropdownMenuCheckboxItem>
</DropdownMenuContent>
</DropdownMenu>Radio Items
Use DropdownMenuRadioGroup and DropdownMenuRadioItem for exclusive selection.
Code
const [theme, setTheme] = useState('system');
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Theme: {theme}</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuRadioGroup value={theme} onValueChange={setTheme}>
<DropdownMenuRadioItem value="light">Light</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="dark">Dark</DropdownMenuRadioItem>
<DropdownMenuRadioItem value="system">System</DropdownMenuRadioItem>
</DropdownMenuRadioGroup>
</DropdownMenuContent>
</DropdownMenu>Sub-menus
Nest DropdownMenuSub for hierarchical menu structures.
Code
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline">Actions</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>New File</DropdownMenuItem>
<DropdownMenuSub>
<DropdownMenuSubTrigger>Share</DropdownMenuSubTrigger>
<DropdownMenuSubContent>
<DropdownMenuItem>Email</DropdownMenuItem>
<DropdownMenuItem>Slack</DropdownMenuItem>
<DropdownMenuItem>Copy Link</DropdownMenuItem>
</DropdownMenuSubContent>
</DropdownMenuSub>
<DropdownMenuSeparator />
<DropdownMenuItem>Delete</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>Controlled Mode
function ControlledMenu() {
const [open, setOpen] = useState(false);
return (
<DropdownMenu open={open} onOpenChange={setOpen}>
<DropdownMenuTrigger asChild>
<Button>Controlled</Button>
</DropdownMenuTrigger>
<DropdownMenuContent>
<DropdownMenuItem>Action</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
);
}Component Architecture
| Component | Description |
|---|---|
DropdownMenu | Root component managing open/close state |
DropdownMenuTrigger | Element that opens the menu on click |
DropdownMenuContent | Floating menu panel with variant styling, rendered via Portal |
DropdownMenuItem | A single actionable menu item |
DropdownMenuSeparator | Horizontal divider between groups |
DropdownMenuLabel | Non-interactive label for grouping items |
DropdownMenuCheckboxItem | Togglable checkbox menu item |
DropdownMenuRadioGroup | Container for exclusive radio selection |
DropdownMenuRadioItem | Radio option within a group |
DropdownMenuSub | Sub-menu container |
DropdownMenuSubTrigger | Item that opens a sub-menu |
DropdownMenuSubContent | Floating panel for sub-menu items |
Props
DropdownMenu (Root)
| Name | Type | Default | Description |
|---|---|---|---|
open | boolean | - | Controlled open state |
defaultOpen | boolean | false | Initial open state for uncontrolled usage |
onOpenChange | (open: boolean) => void | - | Callback when the open state changes |
dir | 'ltr' | 'rtl' | - | Text direction |
modal | boolean | true | When true, traps focus and makes background inert |
DropdownMenuContent
| Name | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'outline' | 'default' | Visual style variant |
side | 'top' | 'bottom' | 'left' | 'right' | 'bottom' | Preferred side to display the menu |
sideOffset | number | 4 | Distance in px between the menu and the trigger |
className | string | - | Additional CSS classes |
DropdownMenuItem
| Name | Type | Default | Description |
|---|---|---|---|
inset | boolean | false | Add left padding to align with labels |
disabled | boolean | false | Disable the item |
onSelect | (event: Event) => void | - | Callback when the item is selected |
DropdownMenuCheckboxItem
| Name | Type | Default | Description |
|---|---|---|---|
checked | boolean | - | Controlled checked state |
onCheckedChange | (checked: boolean) => void | - | Callback when checked state changes |
disabled | boolean | false | Disable the item |
DropdownMenuRadioGroup
| Name | Type | Default | Description |
|---|---|---|---|
value | string | - | Currently selected value |
onValueChange | (value: string) => void | - | Callback when selected value changes |
DropdownMenuSubContent
| Name | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'outline' | 'default' | Visual style variant for the sub-menu panel; matches the values and default of DropdownMenuContent's own variant prop. |
Accessibility
Built on Radix UI DropdownMenu with full accessibility support:
- role="menu": Content is announced as a menu to screen readers
- role="menuitem": Each item is properly identified
- role="menuitemcheckbox": Checkbox items have correct role
- role="menuitemradio": Radio items have correct role
- Focus management: Focus moves into the menu when opened and returns to trigger on close
- Escape key: Pressing Escape dismisses the menu
- Click outside: Clicking outside the menu closes it
- Portal rendering: Content renders outside the DOM hierarchy without affecting the accessibility tree
Keyboard Support
| Key | Action |
|---|---|
| Enter / Space | Open menu (on trigger) or select item |
| Escape | Close the menu |
| Arrow Down | Move focus to next item |
| Arrow Up | Move focus to previous item |
| Arrow Right | Open sub-menu (on sub-trigger) |
| Arrow Left | Close sub-menu |