Android PopupMenu and iOS14+ UIMenu components for react-native.
Falls back to ActionSheet for versions below iOS14.
Installation
via npm:
npm install @react-native-menu/menu
via yarn:
yarn add @react-native-menu/menu
Installing on iOS with React Native 0.63 and above
There is an issue(https://github.com/facebook/react-native/issues/29246) causing projects with this module to fail on build on React Native 0.63 and above.
This issue may be fixed in future versions of react native.
As a work around, look for lines in [YourPrject].xcodeproj
under LIBRARY_SEARCH_PATHS
with "\"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)\"",
and change swift-5.0
to swift-5.3
.
Linking
The package is automatically linked when building the app. All you need to do is:
npx pod-install
Usage
import { MenuView } from '@react-native-menu/menu';
const App = () => {
return (
<View style={styles.container}>
<MenuView
title="Menu Title"
onPressAction={({ nativeEvent }) => {
console.warn(JSON.stringify(nativeEvent));
}}
actions={[
{
id: 'add',
title: 'Add',
titleColor: '#2367A2',
image: Platform.select({
ios: 'plus',
android: 'ic_menu_add',
}),
imageColor: '#2367A2',
subactions: [
{
id: 'nested1',
title: 'Nested action',
titleColor: 'rgba(250,180,100,0.5)',
subtitle: 'State is mixed',
image: Platform.select({
ios: 'heart.fill',
android: 'ic_menu_today',
}),
imageColor: 'rgba(100,200,250,0.3)',
state: 'mixed',
},
{
id: 'nestedDestructive',
title: 'Destructive Action',
attributes: {
destructive: true,
},
image: Platform.select({
ios: 'trash',
android: 'ic_menu_delete',
}),
},
],
},
{
id: 'share',
title: 'Share Action',
titleColor: '#46F289',
subtitle: 'Share action on SNS',
image: Platform.select({
ios: 'square.and.arrow.up',
android: 'ic_menu_share',
}),
imageColor: '#46F289',
state: 'on',
},
{
id: 'destructive',
title: 'Destructive Action',
attributes: {
destructive: true,
},
image: Platform.select({
ios: 'trash',
android: 'ic_menu_delete',
}),
},
]}
shouldOpenOnLongPress={false}
>
<View style={styles.button}>
<Text style={styles.buttonText}>Test</Text>
</View>
</MenuView>
</View>
);
};
Declarative usage
It's also possible to obtain the action
is a more React-ish, declarative fashion. Refer to the react-to-imperative
package, and see an example here.
Reference
Props
title
(iOS only)
The title of the menu.
isAnchoredToRight
(Android only)
Boolean determining if menu should anchored to right or left corner of parent view.
shouldOpenOnLongPress
Boolean determining if menu should open after long press or on normal press
actions
Actions to be displayed in the menu.
Type | Required |
---|
MenuAction[] | Yes |
themeVariant
(iOS only)
String to override theme of the menu. If you want to control theme universally across your app, see this package.
Type | Required |
---|
enum('light', 'dark') | No |
Object representing Menu Action.
export type MenuAction = {
id?: string;
title: string;
titleColor?: number | ColorValue;
subtitle?: string;
attributes?: MenuAttributes;
state?: MenuState;
image?: string;
imageColor?: number | ColorValue;
subactions?: MenuAction[];
};
The attributes indicating the style of the action.
type MenuAttributes = {
destructive?: boolean;
disabled?: boolean;
hidden?: boolean;
};
The state of the action.
type MenuState = 'off' | 'on' | 'mixed';
onPressAction
Callback function that will be called when selecting a menu item.
It will contain id of the given action.
Type | Required |
---|
({nativeEvent}) => void | No |
Testing with Jest
In some cases, you might want to mock the package to test your components. You can do this by using the jest.mock
function.
import type { MenuComponentProps } from '@react-native-menu/menu';
jest.mock('@react-native-menu/menu', () => ({
MenuView: jest.fn((props: MenuComponentProps) => {
const React = require('react');
class MockMenuView extends React.Component {
render() {
return React.createElement(
'View',
{ testID: props.testID },
props.actions.map(action =>
React.createElement('Button', {
key: action.id,
title: action.title,
onPress: () => {
if (action.id && props?.onPressAction) {
props.onPressAction({ nativeEvent: { event: action.id } });
}
},
testID: action.id
})
),
this.props.children
);
}
}
return React.createElement(MockMenuView, props);
})
}));
Contributing
See the contributing guide to learn how to contribute to the repository and the development workflow.
License
MIT