Skip to content

fix(react-native-host): wire dev menu on macOS Fabric root views#4114

Draft
Saadnajmi wants to merge 1 commit intomicrosoft:mainfrom
Saadnajmi:fix/host-macos-fabric-dev-menu
Draft

fix(react-native-host): wire dev menu on macOS Fabric root views#4114
Saadnajmi wants to merge 1 commit intomicrosoft:mainfrom
Saadnajmi:fix/host-macos-fabric-dev-menu

Conversation

@Saadnajmi
Copy link
Copy Markdown
Contributor

@Saadnajmi Saadnajmi commented Apr 28, 2026

Summary

On macOS new architecture, right-clicking the React content of an app that uses host.viewWithModuleName:initialProperties: does nothing — the dev menu never appears. The reasons:

  1. On react-native-macos 0.81+, RCTSurfaceHostingView does override menuForEvent:, but it returns [_devMenu menu] and _devMenu is wired by RCTRootViewFactory — a code path consumers of this host bypass.
  2. On older versions, the Fabric root view (RCTSurfaceHostingProxyRootView / RCTSurfaceHostingView) does not override menuForEvent: at all.

After creating the Fabric root view, this PR:

  • 0.81+ path: runtime-checks [rootView respondsToSelector:@selector(setDevMenu:)], then resolves RCTDevMenu via -usingModule:block: and assigns it via performSelector:. This mirrors what RCTRootViewFactory.mm does upstream.
  • Pre-0.81 fallback: installs an NSClickGestureRecognizer with buttonMask = 1 << 1 whose action fetches RCTDevMenu and calls [NSMenu popUpContextMenu:withEvent:forView:] with [devMenu menu].

Both paths are gated by:

#if defined(RCT_DEV_MENU) && RCT_DEV_MENU && __has_include(<React/RCTDevMenu.h>)
#define RNX_WIRE_DEV_MENU 1
#endif
...
#if defined(RNX_WIRE_DEV_MENU) && TARGET_OS_OSX

so iOS and release builds compile the wiring out entirely. The use of respondsToSelector: + performSelector: (rather than importing <React/RCTSurfaceHostingView.h> and casting) keeps the file compiling against react-native-macos versions that don't have the devMenu property in their public headers.

Relationship to microsoft/react-native-test-app#2757

This is the proper, upstream-aligned fix of a pair. microsoft/react-native-test-app#2757 is a self-contained workaround landed in the test app while this change makes its way through review and into a release; once this ships and the test app picks up the new @rnx-kit/react-native-host, that workaround can be removed.

The two surface different menus on secondary-click:

Any consumer of host.viewWithModuleName: benefits from this PR — not just the test app — which is why it belongs here in the host rather than papered over in each app.

Test plan

  • Build against react-native-macos 0.75 (no setDevMenu:) — fallback gesture-recognizer path is exercised; right-click the React content shows the dev menu.
  • Build against react-native-macos 0.81+ (has setDevMenu:) — property-wiring path is exercised; right-click shows the dev menu.
  • Build for iOS — RNX_WIRE_DEV_MENU block is gated by TARGET_OS_OSX, no behavior change.
  • Build a release configuration — RCT_DEV_MENU is 0, the entire block is compiled out.

🤖 Generated with Claude Code

The Fabric root view returned by `viewWithModuleName:initialProperties:`
does not show the dev menu on right-click on macOS, because:

1. On react-native-macos 0.81+, `RCTSurfaceHostingView.menuForEvent:`
   relies on a `devMenu` property that is normally set by
   `RCTRootViewFactory`, which consumers of this host bypass.
2. On earlier versions, the Fabric root view does not override
   `menuForEvent:` at all.

After creating the Fabric root view, mirror what `RCTRootViewFactory`
does on 0.81+ by setting `devMenu` via the `setDevMenu:` selector when
available. For older versions, install an `NSClickGestureRecognizer`
with the secondary-button mask whose action fetches `RCTDevMenu` via
`-usingModule:block:` and pops up `[devMenu menu]` directly.

Both paths are guarded by `RCT_DEV_MENU` and `__has_include
(<React/RCTDevMenu.h>)` so non-dev builds and platforms without the
dev menu compile out the wiring entirely.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant