A floating context menu with positioning, selection groups, and multiple presentation modes.
import { Menu, SubMenu } from 'heroui-native' ;
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" >
< Menu.Close />
< Menu.Label >...</ Menu.Label >
< Menu.Group >
< Menu.Item >
< Menu.ItemIndicator />
< Menu.ItemTitle >...</ Menu.ItemTitle >
< Menu.ItemDescription >...</ Menu.ItemDescription >
</ Menu.Item >
</ Menu.Group >
< SubMenu >
< SubMenu.Trigger textValue = "..." >
< SubMenu.TriggerIndicator />
...
</ SubMenu.Trigger >
< SubMenu.Content >
< Menu.Item >...</ Menu.Item >
< Menu.Item >...</ Menu.Item >
</ SubMenu.Content >
</ SubMenu >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Menu : Main container that manages open/close state, positioning, and provides context to child components.
Menu.Trigger : Clickable element that toggles the menu visibility.
Menu.Portal : Renders menu content in a portal layer above other content.
Menu.Overlay : Optional background overlay to capture outside clicks and close the menu.
Menu.Content : Container for menu content with two presentation modes: floating popover with positioning and collision detection, or bottom sheet modal.
Menu.Close : Close button that dismisses the menu when pressed.
Menu.Label : Non-interactive section heading text within the menu.
Menu.Group : Groups menu items with optional selection state (none, single, multiple).
Menu.Item : Pressable menu item with animated press feedback. Standalone or within a Group for selection.
Menu.ItemTitle : Primary label text for a menu item.
Menu.ItemDescription : Secondary description text for a menu item.
Menu.ItemIndicator : Visual selection indicator (checkmark or dot) for a menu item.
SubMenu : Root container that manages the expand/collapse state and provides animation context to children.
SubMenu.Trigger : Pressable row that toggles the submenu open/closed. Styled like a regular menu item.
SubMenu.TriggerIndicator : Animated chevron icon (default: chevron-right) that rotates when the submenu opens/closes. Place inside SubMenu.Trigger.
SubMenu.Content : Absolutely positioned container that animates its height when the submenu opens/closes. Place Menu.Item elements inside.
The Menu component uses compound parts to create a floating context menu.
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 220 }>
< Menu.Item >
< Menu.ItemTitle >View Profile</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item >
< Menu.ItemTitle >Settings</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Add secondary description text to menu items alongside titles.
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 260 }>
< Menu.Item className = "items-start" >
< View className = "flex-1" >
< Menu.ItemTitle >New file</ Menu.ItemTitle >
< Menu.ItemDescription >Create a new file</ Menu.ItemDescription >
</ View >
</ Menu.Item >
< Menu.Item className = "items-start" >
< View className = "flex-1" >
< Menu.ItemTitle >Copy link</ Menu.ItemTitle >
< Menu.ItemDescription >Copy the file link</ Menu.ItemDescription >
</ View >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Use Menu.Group with selectionMode="single" to allow one selected item at a time.
const [ theme , setTheme ] = useState < Set < MenuKey >>(() => new Set ([ 'system' ]));
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 180 }>
< Menu.Label >Appearance</ Menu.Label >
< Menu.Group
selectionMode = "single"
selectedKeys = {theme}
onSelectionChange = {setTheme}
>
< Menu.Item id = "light" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Light</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "dark" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Dark</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "system" >
< Menu.ItemIndicator />
< Menu.ItemTitle >System</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Group >
</ Menu.Content >
</ Menu.Portal >
</ Menu >;
Use selectionMode="multiple" to allow selecting multiple items simultaneously.
const [ textStyles , setTextStyles ] = useState < Set < MenuKey >>(
() => new Set ([ 'bold' , 'italic' ])
);
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 250 }>
< Menu.Label >Text Style</ Menu.Label >
< Menu.Group
selectionMode = "multiple"
selectedKeys = {textStyles}
onSelectionChange = {setTextStyles}
>
< Menu.Item id = "bold" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Bold</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "italic" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Italic</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "underline" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Underline</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Group >
</ Menu.Content >
</ Menu.Portal >
</ Menu >;
Nest a SubMenu inside Menu.Content to reveal additional items on press.
< Menu >
< Menu.Trigger asChild >
< Button variant = "secondary" >Editor Menu</ Button >
</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 240 }>
< Menu.Item >
< Menu.ItemTitle >New Space</ Menu.ItemTitle >
</ Menu.Item >
< SubMenu >
< SubMenu.Trigger textValue = "Focus" >
< SubMenu.TriggerIndicator />
< Text className = "flex-1 text-base font-medium text-foreground" >
Focus
</ Text >
</ SubMenu.Trigger >
< SubMenu.Content >
< Menu.Item >
< Menu.ItemTitle >Zen Mode</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item >
< Menu.ItemTitle >Reader Mode</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item >
< Menu.ItemTitle >Lock Tab</ Menu.ItemTitle >
</ Menu.Item >
</ SubMenu.Content >
</ SubMenu >
< Menu.Item >
< Menu.ItemTitle >Heading 1</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Use variant="danger" on a menu item for destructive actions.
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 220 }>
< Menu.Item >
< Menu.ItemTitle >Edit</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item variant = "danger" >
< Menu.ItemTitle >Delete</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Control where the menu appears relative to the trigger.
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" placement = "right" width = { 200 }>
< Menu.Item >
< Menu.ItemTitle >Option A</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item >
< Menu.ItemTitle >Option B</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Use presentation="bottom-sheet" to display menu content as a bottom sheet modal.
< Menu presentation = "bottom-sheet" >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "bottom-sheet" >
< Menu.Item >
< Menu.ItemTitle >Option A</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item >
< Menu.ItemTitle >Option B</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
Use variant="dot" on Menu.ItemIndicator to show a filled circle instead of a checkmark.
< Menu >
< Menu.Trigger >...</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 180 }>
< Menu.Group
selectionMode = "single"
selectedKeys = {alignment}
onSelectionChange = {setAlignment}
>
< Menu.Item id = "left" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Left</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "center" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Center</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "right" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Right</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Group >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
import type { MenuKey } from 'heroui-native' ;
import { Button, Menu, Separator } from 'heroui-native' ;
import { useState } from 'react' ;
import { Text, View } from 'react-native' ;
export default function MenuExample () {
const [ textStyles , setTextStyles ] = useState < Set < MenuKey >>(
() => new Set ([ 'bold' , 'italic' ])
);
const [ alignment , setAlignment ] = useState < Set < MenuKey >>(
() => new Set ([ 'left' ])
);
return (
< Menu >
< Menu.Trigger asChild >
< Button variant = "secondary" >Styles</ Button >
</ Menu.Trigger >
< Menu.Portal >
< Menu.Overlay />
< Menu.Content presentation = "popover" width = { 250 }>
< Menu.Label className = "mb-1" >Text Style</ Menu.Label >
< Menu.Group
selectionMode = "multiple"
selectedKeys = {textStyles}
onSelectionChange = {setTextStyles}
>
< Menu.Item id = "bold" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Bold</ Menu.ItemTitle >
< Text className = "text-sm text-muted" >⌘ B</ Text >
</ Menu.Item >
< Menu.Item id = "italic" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Italic</ Menu.ItemTitle >
< Text className = "text-sm text-muted" >⌘ I</ Text >
</ Menu.Item >
< Menu.Item id = "underline" >
< Menu.ItemIndicator />
< Menu.ItemTitle >Underline</ Menu.ItemTitle >
< Text className = "text-sm text-muted" >⌘ U</ Text >
</ Menu.Item >
</ Menu.Group >
< Separator className = "mx-2 my-2 opacity-75" />
< Menu.Label className = "mb-1" >Text Alignment</ Menu.Label >
< Menu.Group
selectionMode = "single"
selectedKeys = {alignment}
onSelectionChange = {setAlignment}
>
< Menu.Item id = "left" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Left</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "center" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Center</ Menu.ItemTitle >
</ Menu.Item >
< Menu.Item id = "right" >
< Menu.ItemIndicator variant = "dot" />
< Menu.ItemTitle >Right</ Menu.ItemTitle >
</ Menu.Item >
</ Menu.Group >
</ Menu.Content >
</ Menu.Portal >
</ Menu >
);
}
You can find more examples in the GitHub repository .
prop type default description childrenReact.ReactNode- The content of the menu presentation'popover' | 'bottom-sheet''popover'Presentation mode for the menu content isOpenboolean- Controlled open state of the menu isDefaultOpenboolean- Open state when initially rendered (uncontrolled) isDisabledboolean- Whether the menu is disabled animationMenuRootAnimation- Animation configuration for menu root onOpenChange(open: boolean) => void- Callback fired when the menu open state changes ...ViewPropsViewProps- All standard React Native View props are supported
Animation configuration for menu root component. Can be:
"disable-all": Disable all animations including children
true or undefined: Use default animations
prop type default description childrenReact.ReactNode- The trigger element content classNamestring- Additional CSS class for the trigger isDisabledbooleanfalseWhether the trigger is disabled asChildboolean- Render as child element using Slot pattern ...PressablePropsPressableProps- All standard React Native Pressable props are supported
prop type default description childrenReact.ReactNode- The portal content classNamestring- Additional CSS class for the portal container disableFullWindowOverlaybooleanfalseUse a regular View instead of FullWindowOverlay on iOS hostNamestring- Optional name of the host element for the portal forceMountboolean- Force mount the portal regardless of open state
prop type default description classNamestring- Additional CSS class for the overlay closeOnPressbooleantrueWhether to close the menu when the overlay is pressed animationMenuOverlayAnimation- Animation configuration for overlay isAnimatedStyleActivebooleantrueWhether animated styles (react-native-reanimated) are active forceMountboolean- Force mount the overlay regardless of open state ...PressablePropsPressableProps- All standard React Native Pressable props are supported
Animation configuration for menu overlay component. Can be:
false or "disabled": Disable all animations
true or undefined: Use default animations
object: Custom animation configuration
prop type default description state'disabled' | boolean- Disable animations while customizing properties opacity.entering.valueEntryOrExitLayoutTypeFadeIn.duration(200)Custom entering animation for overlay opacity.exiting.valueEntryOrExitLayoutTypeFadeOut.duration(150)Custom exiting animation for overlay
Props when presentation="popover".
prop type default description childrenReact.ReactNode- The menu content presentation'popover'- Presentation mode (must match Menu root) placement'top' | 'bottom' | 'left' | 'right''bottom'Where the menu appears relative to the trigger align'start' | 'center' | 'end''center'Alignment of the menu relative to the trigger avoidCollisionsbooleantrueWhether to reposition to avoid screen edges offsetnumber9Distance from the trigger element in pixels alignOffsetnumber0Offset along the alignment axis in pixels width'content-fit' | 'trigger' | 'full' | number'content-fit'Content width sizing strategy classNamestring- Additional CSS class for the content container animationMenuContentAnimation- Animation configuration for content ...ViewPropsViewProps- All standard React Native View props are supported
Animation configuration for menu popover content component. Can be:
false or "disabled": Disable all animations
true or undefined: Use default animations
object: Custom animation configuration
prop type default description state'disabled' | boolean- Disable animations while customizing properties entering.valueEntryOrExitLayoutTypeScale + fade entering animation Custom entering animation for content exiting.valueEntryOrExitLayoutTypeScale + fade exiting animation Custom exiting animation for content
Props when presentation="bottom-sheet". Extends @gorhom/bottom-sheet BottomSheet props.
prop type default description childrenReact.ReactNode- The bottom sheet content presentation'bottom-sheet'- Presentation mode (must match Menu root) classNamestring- Additional CSS class for the bottom sheet backgroundClassNamestring- Additional CSS class for the background handleIndicatorClassNamestring- Additional CSS class for the handle indicator contentContainerClassNamestring- Additional CSS class for the content container contentContainerPropsOmit<BottomSheetViewProps, 'children'>- Props for the content container animationAnimationDisabled- Set to false or "disabled" to disable animations ...BottomSheetPropsPartial<BottomSheetProps>- All @gorhom/bottom-sheet props are supported
Extends CloseButtonProps. Automatically closes the menu when pressed.
prop type default description iconPropsCloseButtonIconProps- Props for customizing the close icon ...ButtonPropsButtonRootProps- All Button root props are supported
prop type default description childrenReact.ReactNode- The group content (Menu.Item elements) selectionMode'none' | 'single' | 'multiple''none'The type of selection allowed in the group selectedKeysIterable<MenuKey>- Currently selected keys (controlled) defaultSelectedKeysIterable<MenuKey>- Initially selected keys (uncontrolled) isDisabledbooleanfalseWhether the entire group is disabled disabledKeysIterable<MenuKey>- Keys of items that should be disabled shouldCloseOnSelectboolean- Whether selecting an item should close the menu classNamestring- Additional CSS class for the group container onSelectionChange(keys: Set<MenuKey>) => void- Callback fired when the selection changes ...ViewPropsViewProps- All standard React Native View props are supported
prop type default description childrenReact.ReactNode- The label text content classNamestring- Additional CSS class for the label ...TextPropsTextProps- All standard React Native Text props are supported
prop type default description childrenReact.ReactNode | ((props: MenuItemRenderProps) => ReactNode)- Child elements or a render function idMenuKey- Unique identifier, required when inside a Menu.Group variant'default' | 'danger''default'Visual variant of the menu item isDisabledbooleanfalseWhether the item is disabled isSelectedboolean- Controlled selected state for standalone items shouldCloseOnSelectbooleantrueWhether pressing this item should close the menu classNamestring- Additional CSS class for the item animationMenuItemAnimation- Animation configuration for press feedback isAnimatedStyleActivebooleantrueWhether animated styles (react-native-reanimated) are active onSelectedChange(selected: boolean) => void- Callback when standalone item's selected state changes ...PressablePropsPressableProps- All standard React Native Pressable props are supported
Props passed to the render function when children is a function.
prop type description isSelectedbooleanWhether this item is currently selected isDisabledbooleanWhether the item is disabled isPressedSharedValue<boolean>Whether the item is currently pressed variant'default' | 'danger'Visual variant of the item
Animation configuration for menu item press feedback. Can be:
false or "disabled": Disable all item animations
true or undefined: Use default animations
object: Custom animation configuration
prop type default description scale.valuenumber0.98Scale value when pressed scale.timingConfigWithTimingConfig{ duration: 150 }Spring animation configuration for scale backgroundColor.valuestringuseThemeColor('default')Background color shown while pressed backgroundColor.timingConfigWithTimingConfig{ duration: 150 }Animation timing for background color
prop type default description childrenReact.ReactNode- The title text content classNamestring- Additional CSS class for the item title ...TextPropsTextProps- All standard React Native Text props are supported
prop type default description childrenReact.ReactNode- The description text content classNamestring- Additional CSS class for the item description ...TextPropsTextProps- All standard React Native Text props are supported
prop type default description childrenReact.ReactNode- Custom indicator content, defaults to checkmark or dot variant'checkmark' | 'dot''checkmark'Visual variant of the indicator iconPropsMenuItemIndicatorIconProps- Icon configuration (checkmark variant) forceMountbooleantrueForce mount the indicator regardless of selected state classNamestring- Additional CSS class for the item indicator ...ViewPropsViewProps- All standard React Native View props are supported
prop type default description sizenumber16Size of the indicator icon (8 for dot variant) colorstringmutedColor of the indicator icon
prop type default description childrenReact.ReactNode- The sub-menu content (trigger, content, and other items) isOpenboolean- Controlled open state of the sub-menu isDefaultOpenboolean- Open state when initially rendered (uncontrolled) isDisabledbooleanfalseWhether the sub-menu is disabled classNamestring- Additional CSS class for the root container animationSubMenuRootAnimation- Animation configuration for the sub-menu onOpenChange(open: boolean) => void- Callback fired when the sub-menu open state changes ...ViewPropsViewProps- All standard React Native View props are supported
Animation configuration for the SubMenu root component. Can be:
"disable-all": Disable all animations including children
false or "disabled": Disable only root animations
true or undefined: Use default animations
object: Custom animation configuration
prop type default description state'disabled' | boolean- Disable animations while customizing properties rootContent.marginHorizontalnumber-16Margin horizontal when sub-menu is open rootContent.marginVerticalnumber-16Margin vertical when sub-menu is open rootContent.paddingHorizontalnumber6Padding horizontal when sub-menu is open rootContent.paddingTopnumber12Padding top when sub-menu is open rootContent.springConfigWithSpringConfig{ damping: 100, stiffness: 950, mass: 3 }Spring configuration for expand/collapse
prop type default description childrenReact.ReactNode- The trigger content (title, icons, indicator, etc.) textValuestring- Accessible text value announced by screen readers classNamestring- Additional CSS class for the trigger isDisabledbooleanfalseWhether the trigger is disabled asChildboolean- Render as child element using Slot pattern ...PressablePropsPressableProps- All standard React Native Pressable props are supported
Animated indicator icon that rotates when the submenu opens/closes. Defaults to a chevron-right icon.
prop type default description childrenReact.ReactNode- Custom indicator content (replaces default chevron) classNamestring- Additional CSS class for the indicator iconPropsSubMenuTriggerIndicatorIconProps- Icon configuration for the default chevron animationSubMenuTriggerIndicatorAnimation- Animation configuration for indicator rotation isAnimatedStyleActivebooleantrueWhether animated styles (react-native-reanimated) are active ...ViewPropsViewProps- All standard React Native View props are supported
prop type default description sizenumber14Size of the indicator icon colorstringmutedColor of the indicator icon
Animation configuration for the trigger indicator rotation. Can be:
false or "disabled": Disable all animations
true or undefined: Use default animations
object: Custom animation configuration
prop type default description state'disabled' | boolean- Disable animations while customizing properties rotation.value[number, number][0, 90]Rotation values [collapsed, expanded] in degrees rotation.springConfigWithSpringConfig{ damping: 140, stiffness: 1000, mass: 4 }Spring configuration for rotation
prop type default description childrenReact.ReactNode- The submenu items (Menu.Item, Menu.Group, etc.) classNamestring- Additional CSS class for the content container ...PressablePropsPressableProps- All standard React Native Pressable props are supported
Hook to access the menu root context. Must be used within a Menu component.
import { useMenu } from 'heroui-native' ;
const { isOpen , onOpenChange , presentation , isDisabled } = useMenu ();
property type description isOpenbooleanWhether the menu is currently open onOpenChange(open: boolean) => voidCallback to change the open state presentation'popover' | 'bottom-sheet'Current presentation mode isDisabledboolean | undefinedWhether the menu is disabled nativeIDstringUnique identifier for the menu instance
Hook to access the menu item context. Must be used within a Menu.Item component.
import { useMenuItem } from 'heroui-native' ;
const { id , isSelected , isDisabled , variant } = useMenuItem ();
property type description idMenuKey | undefinedItem identifier isSelectedbooleanWhether the item is currently selected isDisabledbooleanWhether the item is disabled variant'default' | 'danger'Visual variant of the item
Hook to access the menu animation context. Must be used within a Menu component.
import { useMenuAnimation } from 'heroui-native' ;
const { progress , isDragging } = useMenuAnimation ();
property type description progressSharedValue<number>Animation progress shared value (0=idle, 1=open, 2=close) isDraggingSharedValue<boolean>Whether the bottom sheet is currently being dragged
Hook to access the sub-menu context. Must be used within a SubMenu component.
import { useSubMenu } from 'heroui-native' ;
const { isOpen , onOpenChange , isDisabled } = useSubMenu ();
property type description isOpenbooleanWhether the sub-menu is currently open onOpenChange(open: boolean) => voidCallback to change the open state isDisabledbooleanWhether the sub-menu is disabled nativeIDstringUnique identifier for the sub-menu instance