Skip to content

Pnlvfx/react-native-context-menu

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

28 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@simonegauli/react-native-context-menu

npm version Platform React Native React License

Native iOS context menus (long-press / 3D Touch) for React Native — built on the New Architecture (Fabric) with a composable, slot-based API.


⚠️ Maintainer notice

I’m building this package in my free time (evenings and weekends), so development moves at a ~weekly cadence. If you need a feature, found a bug, or have any request — please open an issue on GitHub. That helps me prioritise what matters most to the community.


React Compiler

This package is compiled with the React Compiler. The published code is automatically optimized and memoized.


Requirements

  • React Native 0.76+ (Fabric / New Architecture)
  • React 19.0+
  • iOS 13.0+
  • Xcode 15.0+

The old architecture (Paper) is not supported. Make sure newArchEnabled=true in your Podfile / gradle.properties.


Installation

yarn add @simonegauli/react-native-context-menu

Then install the CocoaPods:

cd ios && pod install

Note: Android and Web currently throw a runtime error ("not supported on this platform"). Platform-level stubs will ship in a future release.


Usage

⚠️ Important: React Native's built-in Pressable has a known press/long-press race condition — onPress may fire even when the user intends a long-press to open the context menu. Use react-native-gesture-handler's Pressable instead, which correctly cancels the tap when a long-press is detected. Wrap your app (or at least the screen) in GestureHandlerRootView.

yarn add react-native-gesture-handler
import { StrictMode } from 'react';
import { Alert, StyleSheet, Text, View } from 'react-native';
import {
  GestureHandlerRootView,
  Pressable,
} from 'react-native-gesture-handler';
import * as ContextMenu from '@simonegauli/react-native-context-menu';

export default function App() {
  return (
    <StrictMode>
      <GestureHandlerRootView style={{ flex: 1 }}>
        <View style={styles.container}>
          <ContextMenu.Root>
            <ContextMenu.Trigger>
              <Pressable
                style={styles.box}
                onPress={() => Alert.alert('Button pressed')}
              >
                <Text style={styles.label}>Tap or hold</Text>
              </Pressable>
            </ContextMenu.Trigger>
            <ContextMenu.Content>
              <ContextMenu.Item
                id="share"
                onPress={() => Alert.alert('Share pressed')}
              >
                <ContextMenu.ItemTitle>Share</ContextMenu.ItemTitle>
                <ContextMenu.ItemIcon ios="square.and.arrow.up" />
              </ContextMenu.Item>
              <ContextMenu.Item
                id="copy"
                onPress={() => Alert.alert('Copy pressed')}
              >
                <ContextMenu.ItemTitle>Copy</ContextMenu.ItemTitle>
                <ContextMenu.ItemIcon ios="doc.on.doc" />
              </ContextMenu.Item>
              <ContextMenu.Item
                id="delete"
                destructive
                onPress={() => Alert.alert('Delete pressed')}
              >
                <ContextMenu.ItemTitle>Delete</ContextMenu.ItemTitle>
                <ContextMenu.ItemIcon ios="trash" />
              </ContextMenu.Item>
            </ContextMenu.Content>
          </ContextMenu.Root>
        </View>
      </GestureHandlerRootView>
    </StrictMode>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#1a1a2e',
    alignItems: 'center',
    justifyContent: 'center',
  },
  box: {
    width: 160,
    height: 80,
    borderRadius: 16,
    backgroundColor: 'rgba(255,255,255,0.15)',
    borderWidth: 1,
    borderColor: 'rgba(255,255,255,0.4)',
    alignItems: 'center',
    justifyContent: 'center',
  },
  boxPressed: { backgroundColor: 'rgba(255,255,255,0.3)' },
  label: { color: '#fff', fontWeight: '600', fontSize: 16 },
});

API Reference

ContextMenu.Root

Wraps the context-menu interaction. Must contain one Trigger and one Content.

Prop Type Required Description
children ReactNode Yes Must include a Trigger and a Content
style StyleProp<ViewStyle> No Styles applied to the native wrapper view

ContextMenu.Trigger

Declares the view that receives the long-press / context-menu gesture. Accepts any ReactNode as its single child (typically a Pressable, View, or Image).

On iOS the gesture is handled by UIContextMenuInteraction attached to the native view. Standard tap behaviour (e.g., onPress) is fully preserved.

Prop Type Required Description
children ReactNode Yes The element that triggers the context menu

ContextMenu.Content

Declares the menu items. Only renders Item components — other children are accepted but ignored.

Prop Type Required Description
children ReactNode Yes One or more ContextMenu.Item elements

ContextMenu.Item

A single menu action. Must contain an ItemTitle child.

Prop Type Default Description
id string — (required) Unique identifier for this item
children ReactNode — (required) Must include an ItemTitle
destructive boolean false Renders the item with destructive (red) styling
disabled boolean false Greys-out the item and makes it non-interactive
onPress () => void undefined Callback invoked when the user taps the item

ContextMenu.ItemTitle

Sets the label for the parent Item. Must be a direct child of Item. Children must be a plain string.

Prop Type Required Description
children string Yes Label displayed in the menu

ContextMenu.ItemIcon

Attaches an icon to the parent Item. Must be a direct child of Item. Uses typed SF Symbol names from sf-symbols-typescript for full autocomplete.

Prop Type Platform Description
ios SFSymbol iOS SF Symbol name (e.g. 'trash', 'square.and.arrow.up'). Autocompleted from the full catalogue
androidIconName string Android Android resource drawable name

Roadmap

What’s coming. Ordered roughly by priority — open an issue if you’d like to see something bumped up.

  • Item subtitlesubtitle prop to show a secondary line under each item
  • Item customisation parity — bring feature parity with similar packages such as zeego (inline previews, sub-menus, toggle / stateful items, custom preview providers)
  • Android support — replace the current throw with a real Android PopupMenu / FloatingToolbar implementation
  • Web support — replace the current throw with a working HTML/CSS context menu (native onContextMenu or custom overlay)
  • Platform stubs — render children gracefully on unsupported platforms instead of throwing
  • Expo config plugin — auto-link for managed Expo + CNG setups
  • Menu lifecycle callbacksonMenuWillShow, onMenuWillHide events
  • Dynamic items — update menu contents at runtime without unmounting

Contributing

Contributions are welcome! See CONTRIBUTING.md for the development workflow and pull request guidelines.


License

MIT — see LICENSE.

About

No description, website, or topics provided.

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors