@yyq1025/react-native-context-menu
v0.3.1
Published
Native context menus for React Native — built on Fabric with a composable slot-based API
Maintainers
Readme
@yyq1025/react-native-context-menu
Native iOS context menus (long-press / 3D Touch) for React Native — built on the New Architecture (Fabric) with a composable, slot-based API.
Fork notice
This is a fork of Pnlvfx/react-native-context-menu that fixes a New Architecture crash and improves the lift preview:
- Fabric unmount crash — the context-menu lift reparented the Fabric-tracked view inside virtualized lists (
FlatList/SectionList/ LegendList), so scrolling after opening a menu threwNSInternalInconsistencyException("Attempt to unmount a view which has a different index"). TheUIContextMenuInteractionnow lives on an inner container view, so the lift never moves the view the list indexes. - App-colored preview — the lift shows the row's own (theme-aware) background instead of UIKit's default gray platter.
For these changes, open issues / PRs on yyq1025/react-native-context-menu.
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 @yyq1025/react-native-context-menuThen install the CocoaPods:
cd ios && pod installNote: 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
Pressablehas a known press/long-press race condition —onPressmay fire even when the user intends a long-press to open the context menu. Usereact-native-gesture-handler'sPressableinstead, which correctly cancels the tap when a long-press is detected. Wrap your app (or at least the screen) inGestureHandlerRootView.
yarn add react-native-gesture-handlerimport { StrictMode } from 'react';
import { Alert, StyleSheet, Text, View } from 'react-native';
import {
GestureHandlerRootView,
Pressable,
} from 'react-native-gesture-handler';
import * as ContextMenu from '@yyq1025/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
UIContextMenuInteractionattached 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 subtitle —
subtitleprop 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/FloatingToolbarimplementation - [ ] Web support — replace the current throw with a working HTML/CSS context menu (native
onContextMenuor custom overlay) - [ ] Platform stubs — render
childrengracefully on unsupported platforms instead of throwing - [ ] Expo config plugin — auto-link for managed Expo + CNG setups
- [ ] Menu lifecycle callbacks —
onMenuWillShow,onMenuWillHideevents - [ ] 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.
