Skip to content

A native menu component for React Native that provides platform-specific context menus for both Android and iOS.

License

Notifications You must be signed in to change notification settings

sbaiahmed1/react-native-menus

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

28 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

React Native Menus

A native menu component for React Native that provides platform-specific context menus for both Android and iOS. Pass any custom component as a child to trigger native menus.

Screenshots

iOS Menu
iOS (Native UIMenu)
Android Menu
Android (Modal Dialog)

Features

  • βœ… Native context menu implementation (UIMenu on iOS, Modal on Android)
  • βœ… Custom trigger components - pass any React Native component as a child
  • βœ… Customizable colors for menu items
  • βœ… Checkmark support with custom colors
  • βœ… SF Symbols support on iOS (iosSymbol property)
  • βœ… Subtitle support for menu items
  • βœ… Destructive action styling (Red text)
  • βœ… Theme variant support (Light/Dark/System)
  • βœ… Scrollable menus for long lists
  • βœ… Event handling for menu item selection
  • βœ… TypeScript support
  • βœ… Fabric (New Architecture) compatible
  • βœ… Improved Accessibility support

Installation

npm install react-native-menus
# or
yarn add react-native-menus

iOS Setup

For iOS, run:

cd ios && pod install

Android Setup

No additional setup required for Android.

Usage

Basic Example

import React, { useState } from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { MenuView } from 'react-native-menus';

const App = () => {
  const [selectedTheme, setSelectedTheme] = useState('system');

  const handleMenuSelect = (event: {
    nativeEvent: { identifier: string; title: string };
  }) => {
    setSelectedTheme(event.nativeEvent.identifier);
    console.log('Selected:', event.nativeEvent.title);
  };

  return (
    <View style={styles.container}>
      <MenuView
        checkedColor="#007AFF"
        uncheckedColor="#8E8E93"
        menuItems={[
          { identifier: 'light', title: 'Light Mode' },
          { identifier: 'dark', title: 'Dark Mode' },
          { identifier: 'system', title: 'System Default' },
        ]}
        onMenuSelect={handleMenuSelect}
      >
        <View style={styles.menuButton}>
          <Text style={styles.menuButtonText}>
            πŸŒ“ Theme: {selectedTheme}
          </Text>
        </View>
      </MenuView>
    </View>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
  },
  menuButton: {
    backgroundColor: '#fff',
    paddingHorizontal: 20,
    paddingVertical: 12,
    borderRadius: 8,
    borderWidth: 1,
    borderColor: '#ddd',
  },
  menuButtonText: {
    fontSize: 16,
    color: '#333',
  },
});

export default App;

Controlled Selection (Recommended)

Use the selectedIdentifier prop to fully control which item is marked as selected. Update it in your onMenuSelect handler to keep iOS and Android behavior consistent.

const [selectedSort, setSelectedSort] = useState('date');

<MenuView
  selectedIdentifier={selectedSort}
  menuItems={[
    { identifier: 'date', title: 'Date' },
    { identifier: 'name', title: 'Name' },
    { identifier: 'size', title: 'Size' },
  ]}
  onMenuSelect={({ nativeEvent }) => setSelectedSort(nativeEvent.identifier)}
>
  <View style={styles.menuButton}>
    <Text>πŸ“Š Sort by: {selectedSort}</Text>
  </View>
</MenuView>

Custom Styled Trigger

<MenuView
  menuItems={[
    { identifier: 'profile', title: 'View Profile' },
    { identifier: 'settings', title: 'Settings' },
    { identifier: 'logout', title: 'Logout' },
  ]}
  onMenuSelect={handleMenuSelect}
>
  <View style={styles.customButton}>
    <Text style={styles.customButtonText}>πŸ‘€ Account Menu</Text>
  </View>
</MenuView>

Long Scrollable List

<MenuView
  checkedColor="#5856D6"
  menuItems={[
    { identifier: 'opt1', title: 'Option 1' },
    { identifier: 'opt2', title: 'Option 2' },
    // ... many more items
    { identifier: 'opt20', title: 'Option 20' },
  ]}
  onMenuSelect={handleMenuSelect}
>
  <View style={styles.menuButton}>
    <Text>πŸ“‹ Select Option</Text>
  </View>
</MenuView>

Disabled Menu

const [isDisabled, setIsDisabled] = useState(false);

<MenuView
  disabled={isDisabled}
  menuItems={[
    { identifier: 'enable', title: 'Enable Menu' },
    { identifier: 'disable', title: 'Disable Menu' },
  ]}
  onMenuSelect={({ nativeEvent }) => {
    setIsDisabled(nativeEvent.identifier === 'disable');
  }}
>
  <View style={[styles.menuButton, isDisabled && styles.disabledButton]}>
    <Text style={[styles.menuButtonText, isDisabled && styles.disabledText]}>
      {isDisabled ? 'πŸ”’ Menu Disabled' : 'πŸ”“ Menu Enabled'}
    </Text>
  </View>
</MenuView>

// Add these styles
const styles = StyleSheet.create({
  // ... other styles
});

API Reference

MenuView Props

Prop Type Default Description
menuItems MenuItem[] [] Array of menu items to display
title string undefined Title of the menu (Android only)
androidDisplayMode 'dialog' | 'tooltip' 'dialog' Display mode for the menu on Android (Android only)
themeVariant 'light' | 'dark' | 'system' 'system' Theme variant for the menu background and text (Android only)
selectedIdentifier string undefined Identifier of the currently selected item
checkedColor string '#007AFF' Color of the checkmark for selected items
uncheckedColor string '#8E8E93' Color of the checkmark for unselected items (Android only)
color string undefined Tint color for the menu button text (if using default button)
disabled boolean false Whether the menu is disabled
onMenuSelect (event: NativeSyntheticEvent<MenuSelectEvent>) => void undefined Callback when a menu item is selected

MenuItem Object

Property Type Description
identifier string Unique identifier for the item
title string Text to display
subtitle string Subtitle text (optional)
destructive boolean Whether the item represents a destructive action (red text)
iosSymbol string SF Symbol name (iOS only)

Contributing

See the contributing guide to learn how to contribute to the repository and the development workflow.

License

MIT