# 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
```
### With Item Descriptions
Add secondary description text to menu items alongside titles.
```tsx
```
### Single Selection
Use `Menu.Group` with `selectionMode="single"` to allow one selected item at a time.
```tsx
const [theme, setTheme] = useState>(() => new Set(['system']));
;
```
### Multiple Selection
Use `selectionMode="multiple"` to allow selecting multiple items simultaneously.
```tsx
const [textStyles, setTextStyles] = useState>(
() => new Set(['bold', 'italic'])
);
;
```
### With SubMenu
Nest a `SubMenu` inside `Menu.Content` to reveal additional items on press.
```tsx
```
### Danger Variant
Use `variant="danger"` on a menu item for destructive actions.
```tsx
```
### Placements
Control where the menu appears relative to the trigger.
```tsx
```
### Bottom Sheet Presentation
Use `presentation="bottom-sheet"` to display menu content as a bottom sheet modal.
```tsx
```
### Dot Indicator
Use `variant="dot"` on `Menu.ItemIndicator` to show a filled circle instead of a checkmark.
```tsx
```
## 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 (
);
}
```
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 |