npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-nitro-contextmenu

v2026.2.4

Published

Native context menus built with Nitro Modules

Downloads

261

Readme

react-native-nitro-contextmenu

Native context menus built with Nitro Modules. Supports actions, submenus, selection state, inline groups, palettes, tabbed menus, and tap-to-trigger.

Installation

npm install react-native-nitro-contextmenu react-native-nitro-modules

For iOS, install pods:

cd ios && pod install

Android requires no additional setup.

Quick Start

import { ContextMenu } from "react-native-nitro-contextmenu";
import type { MenuConfig } from "react-native-nitro-contextmenu";

function MyComponent() {
  const menuConfig: MenuConfig = {
    title: "",
    items: [
      { actionKey: "copy", title: "Copy", image: { systemName: "doc.on.doc" } },
      { actionKey: "paste", title: "Paste", image: { systemName: "doc.on.clipboard" } },
      {
        actionKey: "delete",
        title: "Delete",
        image: { systemName: "trash" },
        attributes: ["destructive"],
      },
    ],
  };

  return (
    <ContextMenu menuConfig={menuConfig} onPressAction={(key) => console.log("Selected:", key)}>
      <View style={{ padding: 20 }}>
        <Text>Tap me</Text>
      </View>
    </ContextMenu>
  );
}

Props

| Prop | Type | Description | | ----------------- | ----------------------------- | --------------------------------------------------------- | | menuConfig | MenuConfig | Required. The menu structure to display. | | trigger | 'tap' \| 'longPress' | How the menu is triggered. Default: 'tap'. | | onPressAction | (actionKey: string) => void | Called when a menu action is selected. | | onMenuWillShow | () => void | Called when the menu is about to appear. | | onMenuWillHide | () => void | Called when the menu is about to disappear. | | onPreviewPress | () => void | Called when the user taps the preview (iOS only). | | previewConfig | PreviewConfig | Customize the preview appearance (iOS only). | | children | ReactNode | Required. The trigger content. |

Menu Configuration

MenuConfig

The root menu and any submenus share the same shape:

interface MenuConfig {
  title?: string;
  subtitle?: string; // iOS only
  image?: SystemImage;
  options?: MenuOption[];
  preferredElementSize?: "small" | "medium" | "large"; // iOS 16+
  tabs?: MenuTab[]; // iOS 16+ — when present, items is ignored
  items: MenuElement[];
}

MenuAction

Leaf actions that appear as tappable rows:

interface MenuAction {
  actionKey: string; // Unique key returned in onPressAction
  title: string;
  subtitle?: string; // iOS 15+
  image?: MenuImage; // SF Symbol or URL
  selectedImage?: SystemImage; // Icon when state is 'on' (iOS 17+)
  attributes?: MenuElementAttribute[];
  state?: "on" | "off" | "mixed";
  discoverabilityTitle?: string; // iOS only
}

MenuElement

A union of MenuAction | MenuConfig. The native side discriminates by checking for actionKey (action) vs items (submenu).

Images

// SF Symbol (iOS native, mapped to Android system drawables)
{
  systemName: "star.fill";
}

// URL image (iOS only)
{
  url: "https://example.com/icon.png";
}

On Android, common SF Symbol names are automatically mapped to equivalent android.R.drawable icons. You can also provide your own drawables by adding resources named with dots replaced by underscores (e.g. doc_on_doc.xml for doc.on.doc).

Options

Applied to MenuConfig.options:

| Option | iOS | Android | | -------------------- | ---------------------------------------------- | ------------------------------------------------- | | 'displayInline' | Renders children inline with a separator. | Items added to parent menu with group separators. | | 'destructive' | Renders the submenu title in red. | No visual change. | | 'singleSelection' | Only one child can be state: 'on' at a time. | Exclusive checkable group. | | 'displayAsPalette' | Renders children as a horizontal icon row. | No effect (renders as normal items). |

Attributes

Applied to MenuAction.attributes:

| Attribute | iOS | Android | | ---------------------- | ---------------------------------------- | ------------------------- | | 'destructive' | Red text and icon. | Icon tinted red. | | 'disabled' | Grayed out, not tappable. | Grayed out, not tappable. | | 'hidden' | Not visible in the menu. | Not visible in the menu. | | 'keepsMenuPresented' | Menu stays open after tapping (iOS 16+). | No effect. |

Examples

Submenus

Nest MenuConfig objects inside items to create submenus:

const menuConfig: MenuConfig = {
  title: "",
  items: [
    {
      title: "Sort By",
      image: { systemName: "arrow.up.arrow.down" },
      items: [
        { actionKey: "sort-name", title: "Name" },
        { actionKey: "sort-date", title: "Date" },
        { actionKey: "sort-size", title: "Size" },
      ],
    },
  ],
};

Single Selection

Use singleSelection with state to create radio-style groups:

const [selected, setSelected] = useState('medium')

const menuConfig: MenuConfig = {
  title: 'Text Size',
  items: [
    {
      title: '',
      options: ['displayInline', 'singleSelection'],
      items: [
        { actionKey: 'small', title: 'Small', state: selected === 'small' ? 'on' : 'off' },
        { actionKey: 'medium', title: 'Medium', state: selected === 'medium' ? 'on' : 'off' },
        { actionKey: 'large', title: 'Large', state: selected === 'large' ? 'on' : 'off' },
      ],
    },
  ],
}

<ContextMenu menuConfig={menuConfig} onPressAction={setSelected}>
  {/* ... */}
</ContextMenu>

Inline Groups with Separators

Use displayInline to show items in the same level with visual separators, and preferredElementSize: 'small' for compact icon rows (iOS only):

const menuConfig: MenuConfig = {
  title: "",
  items: [
    {
      title: "",
      options: ["displayInline"],
      preferredElementSize: "small",
      items: [
        { actionKey: "cut", title: "Cut", image: { systemName: "scissors" } },
        { actionKey: "copy", title: "Copy", image: { systemName: "doc.on.doc" } },
        { actionKey: "paste", title: "Paste", image: { systemName: "doc.on.clipboard" } },
      ],
    },
    { actionKey: "select-all", title: "Select All", image: { systemName: "selection.pin.in.out" } },
  ],
};

Palette (iOS only)

Use displayAsPalette for a horizontal icon strip (e.g. color pickers). On Android, items render as a normal list.

const menuConfig: MenuConfig = {
  title: "Color",
  items: [
    {
      title: "",
      options: ["displayInline", "displayAsPalette"],
      items: [
        { actionKey: "red", title: "Red", image: { systemName: "circle.fill" } },
        { actionKey: "green", title: "Green", image: { systemName: "circle.fill" } },
        { actionKey: "blue", title: "Blue", image: { systemName: "circle.fill" } },
      ],
    },
  ],
};

Destructive & Disabled Actions

const menuConfig: MenuConfig = {
  title: "",
  items: [
    { actionKey: "edit", title: "Edit", image: { systemName: "pencil" } },
    { actionKey: "archive", title: "Archive", attributes: ["disabled"] },
    {
      title: "",
      options: ["displayInline"],
      items: [
        {
          actionKey: "delete",
          title: "Delete",
          image: { systemName: "trash" },
          attributes: ["destructive"],
        },
      ],
    },
  ],
};

Tabbed Menu (iOS 16+)

Tabs display a row of buttons at the top of the menu. Tapping a tab swaps the items below without dismissing the menu. When tabs is provided, items is ignored.

const menuConfig: MenuConfig = {
  title: "",
  tabs: [
    {
      tabKey: "sort",
      title: "Sort",
      image: { systemName: "arrow.up.arrow.down" },
      items: [
        { actionKey: "sort-name", title: "Name" },
        { actionKey: "sort-date", title: "Date" },
        { actionKey: "sort-size", title: "Size" },
      ],
    },
    {
      tabKey: "filter",
      title: "Filter",
      image: { systemName: "line.3.horizontal.decrease" },
      items: [
        { actionKey: "filter-images", title: "Images" },
        { actionKey: "filter-videos", title: "Videos" },
      ],
    },
  ],
  items: [],
};

On iOS < 16 and on Android, the tab bar is omitted and the first tab's items are shown as a flat menu.

Trigger Mode

By default, the menu opens on a single tap. Use trigger="longPress" for long-press with preview (iOS):

<ContextMenu menuConfig={menuConfig} trigger="longPress">
  <View>
    <Text>Long press me</Text>
  </View>
</ContextMenu>

On iOS, no preview is shown when trigger is 'tap'.

Preview Configuration (iOS only)

Customize the context menu preview. This has no effect on Android.

<ContextMenu
  menuConfig={menuConfig}
  previewConfig={{
    previewType: "view", // 'view' (default) or 'none'
    preferredCommitStyle: "pop", // 'pop' (default) or 'dismiss'
    backgroundColor: "#ffffff",
    borderRadius: 16,
  }}
  onPreviewPress={() => console.log("Preview tapped")}
>
  {/* ... */}
</ContextMenu>

Type Exports

All types are exported for use in your own code:

import type {
  ContextMenuProps,
  MenuConfig,
  MenuAction,
  MenuElement,
  MenuTab,
  MenuOption,
  MenuElementAttribute,
  MenuElementSize,
  MenuElementState,
  MenuImage,
  SystemImage,
  UrlImage,
  PreviewConfig,
} from "react-native-nitro-contextmenu";

Platform Support

Feature matrix

| Feature | iOS | Android | | -------------------- | ------------------------------------------ | ---------------------------- | | Actions with icons | SF Symbols + URL images | Mapped system drawables | | Submenus | Nested menus | Nested menus | | Inline groups | Separator + inline items | Group separators | | Single selection | Checkmarks | Checkmarks | | Destructive style | Red text + icon | Red icon tint | | Disabled items | Grayed out | Grayed out | | Hidden items | Excluded | Excluded | | Trigger mode | trigger="tap" (default) or "longPress" | trigger="tap" or "longPress" | | Tabbed menus | Tab bar + swappable content (iOS 16+) | First tab shown as flat menu | | Palette mode | Horizontal icon row (iOS 17+) | Normal menu items | | Preview | Customizable preview with commit styles | Not supported | | Subtitles | Below action title (iOS 15+) | Not supported | | keepsMenuPresented | Menu stays open (iOS 16+) | Not supported | | selectedImage | Alternate icon for checked state (iOS 17+) | Not supported |

iOS version requirements

| Feature | Minimum iOS | | ---------------------------------------------------------- | ----------- | | Context menus | 13.0 | | Subtitles | 15.0 | | keepsMenuPresented, preferredElementSize, tabbed menus | 16.0 | | displayAsPalette, selectedImage | 17.0 |

Features are gracefully skipped on older iOS versions and unsupported Android features.

License

MIT