
Security News
npm Adopts OIDC for Trusted Publishing in CI/CD Workflows
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
@react-native-menu/menu
Advanced tools
Android PopupMenu and iOS14+ UIMenu components for react-native. Falls back to ActionSheet for versions below iOS14.
Android | iOS 14+ | iOS 13 |
---|---|---|
![]() | ![]() | ![]() |
via npm:
npm install @react-native-menu/menu
via yarn:
yarn add @react-native-menu/menu
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
.
The package is automatically linked when building the app. All you need to do is:
npx pod-install
import { MenuView, MenuComponentRef } from '@react-native-menu/menu';
// ...
const App = () => {
const menuRef = useRef<MenuComponentRef>(null);
return (
<View style={styles.container}>
<Button
title="Show Menu with ref (Android only)"
onPress={() => menuRef.current?.show()}
/>
<MenuView
ref={menuRef}
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>
);
};
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.
ref
(Android only)Ref to the menu component.
Type | Required |
---|---|
ref | No |
title
(iOS only)The title of the menu.
Type | Required |
---|---|
string | Yes |
isAnchoredToRight
(Android only)Boolean determining if menu should anchored to right or left corner of parent view.
Type | Required |
---|---|
boolean | No |
shouldOpenOnLongPress
Boolean determining if menu should open after long press or on normal press
Type | Required |
---|---|
boolean | No |
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 |
MenuAction
Object representing Menu Action.
export type MenuAction = {
/**
* Identifier of the menu action.
* The value set in this id will be returned when menu is selected.
*/
id?: string;
/**
* The action's title.
*/
title: string;
/**
* (Android only)
* The action's title color.
* @platform Android
*/
titleColor?: number | ColorValue;
/**
* (iOS14+ only)
* An elaborated title that explains the purpose of the action.
* @platform iOS
*/
subtitle?: string;
/**
* The attributes indicating the style of the action.
*/
attributes?: MenuAttributes;
/**
* (iOS14+ only)
* The state of the action.
* @platform iOS
*/
state?: MenuState;
/**
* (Android and iOS13+ only)
* - The action's image.
* - Allows icon name included in project or system (Android) resources drawables and
* in SF Symbol (iOS)
* @example // (iOS)
* image="plus"
* @example // (Android)
* image="ic_menu_add"
*/
image?: string;
/**
* (Android and iOS13+ only)
* - The action's image color.
*/
imageColor?: number | ColorValue;
/**
* (Android and iOS14+ only)
* - Actions to be displayed in the sub menu
* - On Android it does not support nesting next sub menus in sub menu item
*/
subactions?: MenuAction[];
};
MenuAttributes
The attributes indicating the style of the action.
type MenuAttributes = {
/**
* An attribute indicating the destructive style.
*/
destructive?: boolean;
/**
* An attribute indicating the disabled style.
*/
disabled?: boolean;
/**
* An attribute indicating the hidden style.
*/
hidden?: boolean;
};
MenuState
The state of the action.
/**
* The state of the action.
* - off: A constant indicating the menu element is in the “off” state.
* - on: A constant indicating the menu element is in the “on” state.
* - mixed: A constant indicating the menu element is in the “mixed” state.
*/
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 |
onCloseMenu
Callback function that will be called when the menu is dismissed. This event fires at the start of the dismissal, before any animations complete.
Type | Required |
---|---|
() => void | No |
onOpenMenu
Callback function that will be called when the menu is opened. This event fires right before the menu is displayed.
Type | Required |
---|---|
() => void | No |
Example usage:
<MenuView
onOpenMenu={() => {
console.log('Menu was opened');
}}
onCloseMenu={() => {
console.log('Menu was closed');
}}
// ... other props
>
<View>
<Text>Open Menu</Text>
</View>
</MenuView>
You might want to use custom icons in the MenuAction image
attribute. To do so, follow these steps.
Search for your icon on e.g. Material Icons, customize the fill, weight, grade etc.
to your liking and then press the Android
tab and click Download
. This wil download an xml file, e.g.
search_24px.xml
. You can create your own icon or get it somewhere else, as long as it is in a format that Android
understands.
If using bare react-native, copy the downloaded xml file to your android/app/src/main/res/drawable
folder.
If you are using Expo, add a dependency
on @expo/config-plugins, and then you can use
an expo config plugin to copy the file from your assets
folder to the drawable
folder. Copy the config plugin to your app and reference it in your app.json
or app.config.js
in the plugins
section like this:
{
"expo": {
"plugins": [
[
"./plugin/withAndroidDrawables",
{
"drawableFiles": [ "./assets/my_icon.xml" ]
}
]
]
}
}
In your MenuAction
you can now reference the icon using its file name, without the .xml
extension. For example,
image: 'my_icon'
will use the my_icon.xml
file you copied to the drawable folder.
Remember to run a new build to see changes to these icons.
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 },
// Dynamically mock each action
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);
})
}));
See the contributing guide to learn how to contribute to the repository and the development workflow.
MIT
FAQs
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
npm now supports Trusted Publishing with OIDC, enabling secure package publishing directly from CI/CD workflows without relying on long-lived tokens.
Research
/Security News
A RubyGems malware campaign used 60 malicious packages posing as automation tools to steal credentials from social media and marketing tool users.
Security News
The CNA Scorecard ranks CVE issuers by data completeness, revealing major gaps in patch info and software identifiers across thousands of vulnerabilities.