# Menu **Category**: native **URL**: https://www.heroui.com/docs/native/components/menu **Source**: https://raw.githubusercontent.com/heroui-inc/heroui/refs/heads/v3/apps/docs/content/docs/native/components/(collections)/menu.mdx > A floating context menu with positioning, selection groups, and multiple presentation modes. *** ## Import ```tsx import { Menu, SubMenu } from 'heroui-native'; ``` ## Anatomy ```tsx ... ... ... ... ... ... ... ``` - **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. ## Usage ### Basic Usage The Menu component uses compound parts to create a floating context menu. ```tsx ... View Profile Settings ``` ### With Item Descriptions Add secondary description text to menu items alongside titles. ```tsx ... New file Create a new file Copy link Copy the file link ``` ### Single Selection Use `Menu.Group` with `selectionMode="single"` to allow one selected item at a time. ```tsx const [theme, setTheme] = useState>(() => new Set(['system'])); ... Appearance Light Dark System ; ``` ### Multiple Selection Use `selectionMode="multiple"` to allow selecting multiple items simultaneously. ```tsx const [textStyles, setTextStyles] = useState>( () => new Set(['bold', 'italic']) ); ... Text Style Bold Italic Underline ; ``` ### With SubMenu Nest a `SubMenu` inside `Menu.Content` to reveal additional items on press. ```tsx New Space Focus Zen Mode Reader Mode Lock Tab Heading 1 ``` ### Danger Variant Use `variant="danger"` on a menu item for destructive actions. ```tsx ... Edit Delete ``` ### Placements Control where the menu appears relative to the trigger. ```tsx ... Option A Option B ``` ### Bottom Sheet Presentation Use `presentation="bottom-sheet"` to display menu content as a bottom sheet modal. ```tsx ... Option A Option B ``` ### Dot Indicator Use `variant="dot"` on `Menu.ItemIndicator` to show a filled circle instead of a checkmark. ```tsx ... Left Center Right ``` ## Example ```tsx 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>( () => new Set(['bold', 'italic']) ); const [alignment, setAlignment] = useState>( () => new Set(['left']) ); return ( Text Style Bold ⌘ B Italic ⌘ I Underline ⌘ U Text Alignment Left Center Right ); } ``` You can find more examples in the [GitHub repository](). ## API Reference ### Menu | prop | type | default | description | | --------------- | ----------------------------- | ----------- | -------------------------------------------------- | | `children` | `React.ReactNode` | - | The content of the menu | | `presentation` | `'popover' \| 'bottom-sheet'` | `'popover'` | Presentation mode for the menu content | | `isOpen` | `boolean` | - | Controlled open state of the menu | | `isDefaultOpen` | `boolean` | - | Open state when initially rendered (uncontrolled) | | `isDisabled` | `boolean` | - | Whether the menu is disabled | | `animation` | `MenuRootAnimation` | - | Animation configuration for menu root | | `onOpenChange` | `(open: boolean) => void` | - | Callback fired when the menu open state changes | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | #### MenuRootAnimation Animation configuration for menu root component. Can be: - `"disable-all"`: Disable all animations including children - `true` or `undefined`: Use default animations ### Menu.Trigger | prop | type | default | description | | ------------------- | ----------------- | ------- | ------------------------------------------------------- | | `children` | `React.ReactNode` | - | The trigger element content | | `className` | `string` | - | Additional CSS class for the trigger | | `isDisabled` | `boolean` | `false` | Whether the trigger is disabled | | `asChild` | `boolean` | - | Render as child element using Slot pattern | | `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported | ### Menu.Portal | prop | type | default | description | | -------------------------- | ----------------- | ------- | ------------------------------------------------------ | | `children` | `React.ReactNode` | - | The portal content | | `className` | `string` | - | Additional CSS class for the portal container | | `disableFullWindowOverlay` | `boolean` | `false` | Use a regular View instead of FullWindowOverlay on iOS | | `unstable_accessibilityContainerViewIsModal` | `boolean` | `false` | Controls whether VoiceOver treats the overlay window as a modal container. When `true`, VoiceOver is restricted to elements inside the overlay. iOS only. Unstable: may change with react-native-screens updates | | `hostName` | `string` | - | Optional name of the host element for the portal | | `forceMount` | `boolean` | - | Force mount the portal regardless of open state | ### Menu.Overlay | prop | type | default | description | | ----------------------- | ---------------------- | ------- | ------------------------------------------------------------ | | `className` | `string` | - | Additional CSS class for the overlay | | `closeOnPress` | `boolean` | `true` | Whether to close the menu when the overlay is pressed | | `animation` | `MenuOverlayAnimation` | - | Animation configuration for overlay | | `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active | | `forceMount` | `boolean` | - | Force mount the overlay regardless of open state | | `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported | #### MenuOverlayAnimation 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.value` | `EntryOrExitLayoutType` | `FadeIn.duration(200)` | Custom entering animation for overlay | | `opacity.exiting.value` | `EntryOrExitLayoutType` | `FadeOut.duration(150)` | Custom exiting animation for overlay | ### Menu.Content (Popover) Props when `presentation="popover"`. | prop | type | default | description | | ----------------- | ------------------------------------------------ | --------------- | -------------------------------------------------- | | `children` | `React.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 | | `avoidCollisions` | `boolean` | `true` | Whether to reposition to avoid screen edges | | `offset` | `number` | `9` | Distance from the trigger element in pixels | | `alignOffset` | `number` | `0` | Offset along the alignment axis in pixels | | `width` | `'content-fit' \| 'trigger' \| 'full' \| number` | `'content-fit'` | Content width sizing strategy | | `className` | `string` | - | Additional CSS class for the content container | | `animation` | `MenuContentAnimation` | - | Animation configuration for content | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | #### MenuContentAnimation 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.value` | `EntryOrExitLayoutType` | Scale + fade entering animation | Custom entering animation for content | | `exiting.value` | `EntryOrExitLayoutType` | Scale + fade exiting animation | Custom exiting animation for content | ### Menu.Content (Bottom Sheet) Props when `presentation="bottom-sheet"`. Extends `@gorhom/bottom-sheet` BottomSheet props. | prop | type | default | description | | --------------------------- | ---------------------------------------- | ------- | ---------------------------------------------------- | | `children` | `React.ReactNode` | - | The bottom sheet content | | `presentation` | `'bottom-sheet'` | - | Presentation mode (must match Menu root) | | `className` | `string` | - | Additional CSS class for the bottom sheet | | `backgroundClassName` | `string` | - | Additional CSS class for the background | | `handleIndicatorClassName` | `string` | - | Additional CSS class for the handle indicator | | `contentContainerClassName` | `string` | - | Additional CSS class for the content container | | `contentContainerProps` | `Omit` | - | Props for the content container | | `animation` | `AnimationDisabled` | - | Set to `false` or `"disabled"` to disable animations | | `...BottomSheetProps` | `Partial` | - | All `@gorhom/bottom-sheet` props are supported | ### Menu.Close Extends `CloseButtonProps`. Automatically closes the menu when pressed. | prop | type | default | description | | ---------------- | ---------------------- | ------- | ------------------------------------ | | `iconProps` | `CloseButtonIconProps` | - | Props for customizing the close icon | | `...ButtonProps` | `ButtonRootProps` | - | All Button root props are supported | ### Menu.Group | prop | type | default | description | | --------------------- | ---------------------------------- | -------- | -------------------------------------------------- | | `children` | `React.ReactNode` | - | The group content (Menu.Item elements) | | `selectionMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | The type of selection allowed in the group | | `selectedKeys` | `Iterable` | - | Currently selected keys (controlled) | | `defaultSelectedKeys` | `Iterable` | - | Initially selected keys (uncontrolled) | | `isDisabled` | `boolean` | `false` | Whether the entire group is disabled | | `disabledKeys` | `Iterable` | - | Keys of items that should be disabled | | `shouldCloseOnSelect` | `boolean` | - | Whether selecting an item should close the menu | | `className` | `string` | - | Additional CSS class for the group container | | `onSelectionChange` | `(keys: Set) => void` | - | Callback fired when the selection changes | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | ### Menu.Label | prop | type | default | description | | -------------- | ----------------- | ------- | -------------------------------------------------- | | `children` | `React.ReactNode` | - | The label text content | | `className` | `string` | - | Additional CSS class for the label | | `...TextProps` | `TextProps` | - | All standard React Native Text props are supported | ### Menu.Item | prop | type | default | description | | ----------------------- | ---------------------------------------------------------------- | ----------- | ------------------------------------------------------------ | | `children` | `React.ReactNode \| ((props: MenuItemRenderProps) => ReactNode)` | - | Child elements or a render function | | `id` | `MenuKey` | - | Unique identifier, required when inside a Menu.Group | | `variant` | `'default' \| 'danger'` | `'default'` | Visual variant of the menu item | | `isDisabled` | `boolean` | `false` | Whether the item is disabled | | `isSelected` | `boolean` | - | Controlled selected state for standalone items | | `shouldCloseOnSelect` | `boolean` | `true` | Whether pressing this item should close the menu | | `className` | `string` | - | Additional CSS class for the item | | `animation` | `MenuItemAnimation` | - | Animation configuration for press feedback | | `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active | | `onSelectedChange` | `(selected: boolean) => void` | - | Callback when standalone item's selected state changes | | `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported | #### MenuItemRenderProps Props passed to the render function when `children` is a function. | prop | type | description | | ------------ | ----------------------- | --------------------------------------- | | `isSelected` | `boolean` | Whether this item is currently selected | | `isDisabled` | `boolean` | Whether the item is disabled | | `isPressed` | `SharedValue` | Whether the item is currently pressed | | `variant` | `'default' \| 'danger'` | Visual variant of the item | #### MenuItemAnimation 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.value` | `number` | `0.98` | Scale value when pressed | | `scale.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Spring animation configuration for scale | | `backgroundColor.value` | `string` | `useThemeColor('default')` | Background color shown while pressed | | `backgroundColor.timingConfig` | `WithTimingConfig` | `{ duration: 150 }` | Animation timing for background color | ### Menu.ItemTitle | prop | type | default | description | | -------------- | ----------------- | ------- | -------------------------------------------------- | | `children` | `React.ReactNode` | - | The title text content | | `className` | `string` | - | Additional CSS class for the item title | | `...TextProps` | `TextProps` | - | All standard React Native Text props are supported | ### Menu.ItemDescription | prop | type | default | description | | -------------- | ----------------- | ------- | -------------------------------------------------- | | `children` | `React.ReactNode` | - | The description text content | | `className` | `string` | - | Additional CSS class for the item description | | `...TextProps` | `TextProps` | - | All standard React Native Text props are supported | ### Menu.ItemIndicator | prop | type | default | description | | -------------- | ---------------------------- | ------------- | ------------------------------------------------------ | | `children` | `React.ReactNode` | - | Custom indicator content, defaults to checkmark or dot | | `variant` | `'checkmark' \| 'dot'` | `'checkmark'` | Visual variant of the indicator | | `iconProps` | `MenuItemIndicatorIconProps` | - | Icon configuration (checkmark variant) | | `forceMount` | `boolean` | `true` | Force mount the indicator regardless of selected state | | `className` | `string` | - | Additional CSS class for the item indicator | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | #### MenuItemIndicatorIconProps | prop | type | default | description | | ------- | -------- | ------- | ---------------------------------------------- | | `size` | `number` | `16` | Size of the indicator icon (8 for dot variant) | | `color` | `string` | `muted` | Color of the indicator icon | ### SubMenu | prop | type | default | description | | --------------- | ------------------------- | ------- | -------------------------------------------------------- | | `children` | `React.ReactNode` | - | The sub-menu content (trigger, content, and other items) | | `isOpen` | `boolean` | - | Controlled open state of the sub-menu | | `isDefaultOpen` | `boolean` | - | Open state when initially rendered (uncontrolled) | | `isDisabled` | `boolean` | `false` | Whether the sub-menu is disabled | | `className` | `string` | - | Additional CSS class for the root container | | `animation` | `SubMenuRootAnimation` | - | Animation configuration for the sub-menu | | `onOpenChange` | `(open: boolean) => void` | - | Callback fired when the sub-menu open state changes | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | ##### SubMenuRootAnimation 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.marginHorizontal` | `number` | `-16` | Margin horizontal when sub-menu is open | | `rootContent.marginVertical` | `number` | `-16` | Margin vertical when sub-menu is open | | `rootContent.paddingHorizontal` | `number` | `6` | Padding horizontal when sub-menu is open | | `rootContent.paddingTop` | `number` | `12` | Padding top when sub-menu is open | | `rootContent.springConfig` | `WithSpringConfig` | `{ damping: 100, stiffness: 950, mass: 3 }` | Spring configuration for expand/collapse | #### SubMenu.Trigger | prop | type | default | description | | ------------------- | ----------------- | ------- | ------------------------------------------------------- | | `children` | `React.ReactNode` | - | The trigger content (title, icons, indicator, etc.) | | `textValue` | `string` | - | Accessible text value announced by screen readers | | `className` | `string` | - | Additional CSS class for the trigger | | `isDisabled` | `boolean` | `false` | Whether the trigger is disabled | | `asChild` | `boolean` | - | Render as child element using Slot pattern | | `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported | #### SubMenu.TriggerIndicator Animated indicator icon that rotates when the submenu opens/closes. Defaults to a chevron-right icon. | prop | type | default | description | | ----------------------- | ---------------------------------- | ------- | ------------------------------------------------------------ | | `children` | `React.ReactNode` | - | Custom indicator content (replaces default chevron) | | `className` | `string` | - | Additional CSS class for the indicator | | `iconProps` | `SubMenuTriggerIndicatorIconProps` | - | Icon configuration for the default chevron | | `animation` | `SubMenuTriggerIndicatorAnimation` | - | Animation configuration for indicator rotation | | `isAnimatedStyleActive` | `boolean` | `true` | Whether animated styles (react-native-reanimated) are active | | `...ViewProps` | `ViewProps` | - | All standard React Native View props are supported | ##### SubMenuTriggerIndicatorIconProps | prop | type | default | description | | ------- | -------- | ------- | --------------------------- | | `size` | `number` | `14` | Size of the indicator icon | | `color` | `string` | `muted` | Color of the indicator icon | ##### SubMenuTriggerIndicatorAnimation 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.springConfig` | `WithSpringConfig` | `{ damping: 140, stiffness: 1000, mass: 4 }` | Spring configuration for rotation | #### SubMenu.Content | prop | type | default | description | | ------------------- | ----------------- | ------- | ------------------------------------------------------- | | `children` | `React.ReactNode` | - | The submenu items (Menu.Item, Menu.Group, etc.) | | `className` | `string` | - | Additional CSS class for the content container | | `...PressableProps` | `PressableProps` | - | All standard React Native Pressable props are supported | ## Hooks ### useMenu Hook to access the menu root context. Must be used within a `Menu` component. ```tsx import { useMenu } from 'heroui-native'; const { isOpen, onOpenChange, presentation, isDisabled } = useMenu(); ``` #### Returns | property | type | description | | -------------- | ----------------------------- | --------------------------------------- | | `isOpen` | `boolean` | Whether the menu is currently open | | `onOpenChange` | `(open: boolean) => void` | Callback to change the open state | | `presentation` | `'popover' \| 'bottom-sheet'` | Current presentation mode | | `isDisabled` | `boolean \| undefined` | Whether the menu is disabled | | `nativeID` | `string` | Unique identifier for the menu instance | ### useMenuItem Hook to access the menu item context. Must be used within a `Menu.Item` component. ```tsx import { useMenuItem } from 'heroui-native'; const { id, isSelected, isDisabled, variant } = useMenuItem(); ``` #### Returns | property | type | description | | ------------ | ----------------------- | -------------------------------------- | | `id` | `MenuKey \| undefined` | Item identifier | | `isSelected` | `boolean` | Whether the item is currently selected | | `isDisabled` | `boolean` | Whether the item is disabled | | `variant` | `'default' \| 'danger'` | Visual variant of the item | ### useMenuAnimation Hook to access the menu animation context. Must be used within a `Menu` component. ```tsx import { useMenuAnimation } from 'heroui-native'; const { progress, isDragging } = useMenuAnimation(); ``` #### Returns | property | type | description | | ------------ | ---------------------- | --------------------------------------------------------- | | `progress` | `SharedValue` | Animation progress shared value (0=idle, 1=open, 2=close) | | `isDragging` | `SharedValue` | Whether the bottom sheet is currently being dragged | ### useSubMenu Hook to access the sub-menu context. Must be used within a `SubMenu` component. ```tsx import { useSubMenu } from 'heroui-native'; const { isOpen, onOpenChange, isDisabled } = useSubMenu(); ``` #### Returns | property | type | description | | -------------- | ------------------------- | ------------------------------------------- | | `isOpen` | `boolean` | Whether the sub-menu is currently open | | `onOpenChange` | `(open: boolean) => void` | Callback to change the open state | | `isDisabled` | `boolean` | Whether the sub-menu is disabled | | `nativeID` | `string` | Unique identifier for the sub-menu instance |