Dropdown Menu

A versatile dropdown menu component with nested sub-menus, positioning, and animations.

Installation

Install the component:

npx natively-ui add dropdown-menu

Usage

DropdownMenuDemo.jsx
1import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from '@/components/ui/dropdown-menu'; 2 3export default function MyComponent() { 4 return ( 5 <DropdownMenu> 6 <DropdownMenuTrigger> 7 <Button>Open Menu</Button> 8 </DropdownMenuTrigger> 9 <DropdownMenuContent> 10 <DropdownMenuItem onPress={() => console.log('Item pressed')}> 11 Menu Item 12 </DropdownMenuItem> 13 </DropdownMenuContent> 14 </DropdownMenu> 15 ); 16}

Components

DropdownMenu

The root container for the dropdown menu.

PropTypeDefaultDescription
childrenReactNode-The content of the dropdown menu.

DropdownMenuTrigger

The element that triggers the dropdown menu.

PropTypeDefaultDescription
childrenReactNode-The trigger element content.
asChildbooleanfalseWhen true, merges props with the first child element instead of wrapping it.

DropdownMenuContent

The dropdown menu content container.

PropTypeDefaultDescription
childrenReactNode-The menu items and content.
classNamestring""Additional CSS classes for styling.
sideOffsetnumber4Distance between trigger and content.
align'start' | 'center' | 'end''start'Alignment of the dropdown relative to trigger.

DropdownMenuItem

An individual menu item.

PropTypeDefaultDescription
childrenReactNode-The menu item content.
classNamestring""Additional CSS classes for styling.
disabledbooleanfalseWhether the menu item is disabled.
onPress() => void-Function called when the item is pressed.

Features

  • Smooth animations with React Native Reanimated
  • Smart positioning that adjusts to screen boundaries
  • Nested sub-menus with portal rendering
  • Keyboard shortcuts display support
  • Menu items with disabled states
  • Customizable alignment and spacing
  • Dark mode support
  • Scrollable content for long menus
  • Auto-close on item selection or outside press

Examples

Basic Menu

BasicMenuDemo.jsx
1<DropdownMenu> 2 <DropdownMenuTrigger> 3 <Button>Options</Button> 4 </DropdownMenuTrigger> 5 <DropdownMenuContent> 6 <DropdownMenuItem onPress={() => console.log('Profile')}> 7 <Text>Profile</Text> 8 </DropdownMenuItem> 9 <DropdownMenuSeparator /> 10 <DropdownMenuItem onPress={() => console.log('Settings')}> 11 <Text>Settings</Text> 12 </DropdownMenuItem> 13 <DropdownMenuItem disabled> 14 <Text>Disabled Item</Text> 15 </DropdownMenuItem> 16 </DropdownMenuContent> 17</DropdownMenu>

With Icons and Shortcuts

IconMenuDemo.jsx
1<DropdownMenu> 2 <DropdownMenuTrigger asChild> 3 <Button variant="outline"> 4 <Icon name="more-horizontal" size={16} /> 5 </Button> 6 </DropdownMenuTrigger> 7 <DropdownMenuContent> 8 <DropdownMenuLabel>Actions</DropdownMenuLabel> 9 <DropdownMenuSeparator /> 10 11 <DropdownMenuItem onPress={() => console.log('Copy')}> 12 <Icon name="copy" size={16} style={{ marginRight: 8 }} /> 13 <Text>Copy</Text> 14 <DropdownMenuShortcut>⌘+C</DropdownMenuShortcut> 15 </DropdownMenuItem> 16 17 <DropdownMenuItem onPress={() => console.log('Cut')}> 18 <Icon name="scissors" size={16} style={{ marginRight: 8 }} /> 19 <Text>Cut</Text> 20 <DropdownMenuShortcut>⌘+X</DropdownMenuShortcut> 21 </DropdownMenuItem> 22 23 <DropdownMenuItem onPress={() => console.log('Paste')}> 24 <Icon name="clipboard" size={16} style={{ marginRight: 8 }} /> 25 <Text>Paste</Text> 26 <DropdownMenuShortcut>⌘+V</DropdownMenuShortcut> 27 </DropdownMenuItem> 28 </DropdownMenuContent> 29</DropdownMenu>

Sub Menu

SubMenuDemo.jsx
1<DropdownMenu> 2 <DropdownMenuTrigger> 3 <Button>Menu with Submenu</Button> 4 </DropdownMenuTrigger> 5 <DropdownMenuContent> 6 <DropdownMenuItem> 7 <Text>New File</Text> 8 </DropdownMenuItem> 9 10 <DropdownMenuSub> 11 <DropdownMenuSubTrigger> 12 <Icon name="share" size={16} style={{ marginRight: 8 }} /> 13 <Text>Share</Text> 14 </DropdownMenuSubTrigger> 15 <DropdownMenuPortal> 16 <DropdownMenuSubContent> 17 <DropdownMenuItem onPress={() => console.log('Email')}> 18 <Icon name="mail" size={16} style={{ marginRight: 8 }} /> 19 <Text>Email</Text> 20 </DropdownMenuItem> 21 <DropdownMenuItem onPress={() => console.log('Message')}> 22 <Icon name="message-square" size={16} style={{ marginRight: 8 }} /> 23 <Text>Message</Text> 24 </DropdownMenuItem> 25 <DropdownMenuItem onPress={() => console.log('Copy Link')}> 26 <Icon name="link" size={16} style={{ marginRight: 8 }} /> 27 <Text>Copy Link</Text> 28 </DropdownMenuItem> 29 </DropdownMenuSubContent> 30 </DropdownMenuPortal> 31 </DropdownMenuSub> 32 33 <DropdownMenuSeparator /> 34 <DropdownMenuItem> 35 <Text>Delete</Text> 36 </DropdownMenuItem> 37 </DropdownMenuContent> 38</DropdownMenu>

Alignment Options

AlignmentDemo.jsx
1<View style={{ gap: 16, flexDirection: 'row' }}> 2 {/* Start aligned */} 3 <DropdownMenu> 4 <DropdownMenuTrigger> 5 <Button>Start</Button> 6 </DropdownMenuTrigger> 7 <DropdownMenuContent align="start"> 8 <DropdownMenuItem><Text>Left aligned</Text></DropdownMenuItem> 9 <DropdownMenuItem><Text>Menu item</Text></DropdownMenuItem> 10 </DropdownMenuContent> 11 </DropdownMenu> 12 13 {/* Center aligned */} 14 <DropdownMenu> 15 <DropdownMenuTrigger> 16 <Button>Center</Button> 17 </DropdownMenuTrigger> 18 <DropdownMenuContent align="center"> 19 <DropdownMenuItem><Text>Center aligned</Text></DropdownMenuItem> 20 <DropdownMenuItem><Text>Menu item</Text></DropdownMenuItem> 21 </DropdownMenuContent> 22 </DropdownMenu> 23 24 {/* End aligned */} 25 <DropdownMenu> 26 <DropdownMenuTrigger> 27 <Button>End</Button> 28 </DropdownMenuTrigger> 29 <DropdownMenuContent align="end"> 30 <DropdownMenuItem><Text>Right aligned</Text></DropdownMenuItem> 31 <DropdownMenuItem><Text>Menu item</Text></DropdownMenuItem> 32 </DropdownMenuContent> 33 </DropdownMenu> 34</View>

As Context Menu

ContextMenuDemo.jsx
1function ContextMenuExample() { 2 const [selectedItem, setSelectedItem] = useState(null); 3 4 return ( 5 <View style={{ padding: 20 }}> 6 <DropdownMenu> 7 <DropdownMenuTrigger asChild> 8 <Pressable 9 style={{ 10 padding: 20, 11 backgroundColor: '#f3f4f6', 12 borderRadius: 8, 13 borderWidth: 2, 14 borderStyle: 'dashed', 15 borderColor: '#d1d5db' 16 }} 17 > 18 <Text style={{ textAlign: 'center' }}> 19 Right click me (or tap on mobile) 20 </Text> 21 </Pressable> 22 </DropdownMenuTrigger> 23 24 <DropdownMenuContent> 25 <DropdownMenuGroup> 26 <DropdownMenuLabel>Actions</DropdownMenuLabel> 27 <DropdownMenuItem onPress={() => setSelectedItem('edit')}> 28 <Text>Edit</Text> 29 </DropdownMenuItem> 30 <DropdownMenuItem onPress={() => setSelectedItem('duplicate')}> 31 <Text>Duplicate</Text> 32 </DropdownMenuItem> 33 </DropdownMenuGroup> 34 35 <DropdownMenuSeparator /> 36 37 <DropdownMenuItem 38 onPress={() => setSelectedItem('delete')} 39 className="text-red-600" 40 > 41 <Text style={{ color: '#dc2626' }}>Delete</Text> 42 </DropdownMenuItem> 43 </DropdownMenuContent> 44 </DropdownMenu> 45 46 {selectedItem && ( 47 <Text style={{ marginTop: 16 }}> 48 Selected: {selectedItem} 49 </Text> 50 )} 51 </View> 52 ); 53}