Skip to main content
Version: v0.30.x

Menu

Menu drops a list of actions from the button that opens it: the β‹― on a card, a "Sort" button, a toolbar icon. Long-press instead, and it's a context menu. It takes the same actions as ActionSheet, and presentation="sheet" opens them as one.

It's pure JavaScript, so unlike native menus it runs in Expo Go and on the web, and looks the same as the rest of your pickers: iOS, Material or web.

import { Menu } from '@elik56a/react-native-pickers';
Loading…
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between' }}>
  <Text>Last action: {last}</Text>
  <Menu
    actions={[
      { label: 'Edit', icon: icon('✏️'), onPress: () => setLast('Edit') },
      { label: 'Duplicate', icon: icon('πŸ“„'), onPress: () => setLast('Duplicate') },
      { label: 'Pin to top', icon: icon('πŸ“Œ'), selected: pinned, onPress: () => setPinned((p) => !p) },
      { label: 'Delete', icon: icon('πŸ—‘οΈ'), destructive: true, onPress: () => setLast('Delete') },
    ]}
  >
    {({ open }) => (
      <DemoButton size="icon" variant="secondary" title="β‹―" accessibilityLabel="Note options" onPress={open} />
    )}
  </Menu>
</View>

Try the props​

Platform
align
title
presentation
<Menu actions={actions} accessibilityLabel="Note options">
…
</Menu>

Actions​

Each action is the same as in an ActionSheet: { label, onPress, description, icon, selected, destructive, disabled, testID }. A tap closes the menu and onPress runs once it has closed, so an action can open a sheet or a modal.

The iOS design puts icons after the label with a hairline between actions, as iOS menus do; Material and the web put them first.

The trigger​

children is the trigger. A node is wrapped in a pressable that opens the menu; name it for screen readers with accessibilityLabel. To use your own button, pass a function: it gets open and visible.

This one is a "Sort" button with a title, a βœ“ on the current order and a line under each choice:

Loading…
<View style={{ alignItems: 'center' }}>
  <Menu
    title="Sort results by"
    actions={SORTS.map((s) => ({ ...s, selected: s.label === sort, onPress: () => setSort(s.label) }))}
  >
    {({ open, visible }) => (
      <DemoButton size="sm" variant="secondary" title={`Sort: ${sort} ${visible ? 'β–΄' : 'β–Ύ'}`} onPress={open} />
    )}
  </Menu>
</View>

Context menu​

openOnLongPress opens the menu on a long press instead of a tap, as a message bubble or a photo does.

Loading…
<View style={{ alignItems: 'center' }}>
  <Menu
    openOnLongPress
    accessibilityLabel="Message, long-press for options"
    actions={[
      { label: 'Reply' },
      { label: 'Copy' },
      { label: 'Forward', description: 'To a chat or a group' },
      { label: 'Delete', destructive: true },
    ]}
    styles={{
      trigger: {
        backgroundColor: colors.primary,
        paddingVertical: 10,
        paddingHorizontal: 14,
        borderRadius: 18,
        borderBottomRightRadius: 4,
      },
    }}
  >
    <Text style={{ color: colors.onPrimary, fontSize: 15 }}>Long-press me πŸ‘‹</Text>
  </Menu>
</View>

Where it opens​

The menu opens under the trigger, or above it when there's more room there. align picks the edge it lines up with:

  • 'auto' (default): the trigger's left edge, or its right edge when the trigger sits in the right half of the window, so a β‹― at the end of a row opens inwards.
  • 'start' / 'end': the trigger's start or end edge, flipped in right-to-left layouts.

width sets the menu's width: 250 in the iOS design and 200 otherwise.

presentation="sheet" opens the same actions as an ActionSheet instead, from the bottom of the screen.

Accessibility​

The trigger is a button that reports whether the menu is expanded. Each action is a button named by its label and description, marked disabled or selected. A tap outside, Android's Back and Escape on the web close the menu, and on the web arrow keys move between actions.

Props​

PropTypeDefaultDescription
actionsMenuAction[]requiredThe actions, top to bottom. Same shape as ActionSheetAction.
childrenReactNode | ({ open, visible }) => ReactNoderequiredThe trigger: a node that opens the menu, or a function for your own button.
titlestringβ€”A small heading above the actions.
align'auto' | 'start' | 'end''auto'The trigger edge the menu lines up with.
widthnumber250 iOS / 200 otherThe menu's width.
presentation'menu' | 'sheet''menu'A menu by the trigger, or an action sheet.
openOnLongPressbooleanfalseOpen on a long press, as a context menu.
disabledbooleanfalseThe trigger doesn't open the menu.
onOpen / onClose() => voidβ€”When it opens; when it closes for any reason, before an action runs.
accessibilityLabelstringβ€”What screen readers call the trigger, such as 'More options'.
themeDeepPartial<PickerTheme>β€”Theme override. See Theming.
design'ios' | 'material' | 'web'from PickersProviderThe look to follow, over the provider's: iOS, Material or web.
styleStyleProp<ViewStyle>β€”The box around the trigger.
stylesSlotStyles<MenuSlot>β€”Slot styles: trigger (the pressable around a node trigger), menu, header, title, action, actionLabel, actionDescription, check.
testIDstringβ€”On the trigger; the menu gets ${testID}-menu.