react-native-web
react-native-web copied to clipboard
Unable to interact with nested Pressables if parent is disabled
Is there an existing issue for this?
- [X] I have searched the existing issues
Describe the issue
Hovering Pressables inside of another, disabled pressable no longer works.
Expected behavior
I would expect this behavior to be the same as in 0.17.x, where hovering of Pressables nested inside a disabled Pressable was possible.
Steps to reproduce
- Install
[email protected] - Wrap a pressable within another pressable, and add a visual hover state to it through a nested view or similar.
- Disable the parent pressable
- Attempt to trigger the hover-state for the nested pressable. You should be successful!
then...
- Install
[email protected] - Repeat steps 2 & 3 from the previous steps
- Attempt to trigger the hover state for the nested pressable. Nothing should happen.
This scenario has already been set up in the provided CodeSandbox. Just change the version of the react-native-web package!
Test case
https://codesandbox.io/s/react-native-web-pressable-nesting-zjo2sz
Additional comments
I can't seem to find any references to this particular change, so I'm not sure whether this is a regression or an intended behavior change.
I'm very thankful for this project and all the work that goes into improving it! 🙌
It will have been this change https://github.com/necolas/react-native-web/commit/094bd0efc5ac1c566a81dec7ee825deae2c5a9a7
I'm not sure why the contents of a disabled element would be expected to be interactive. If anything, it was a bug in 0.17 that they were
I understand and I kind of agree! My use case is something like the following:

I want the area encircled with red color to be clickable to toggle the collapsible. I also want the buttons encircled in blue to be visible and interactive at all times. As mentioned, this can be worked around - but not as convenient as before.
Here are two possible alternatives:
None of these fulfill the same requirement as the first one. Or actually, perhaps the second one could if pointer events had been turned off for the blue container and explicitly turned on again for the buttons themselves. Needless to say, it is possible to work around this. As mentioned already, I agree with you and just opened this in case it was an unintended regression.
If you have a suggestion on how to solve this in a better way than what is mentioned above then that would be most welcome, and if not - feel free to close this! 🙌
So are you disabling the red-outlined pressable in some circumstances, but want the blue ones to remain interactive?
Yes, that's correct!
Am also running into this issue whilst upgrading to [email protected], with a use case very similar hierarchically to that outlined in https://github.com/necolas/react-native-web/issues/2391#issuecomment-1235794950.
I've recreated the Test case from the initial report, this time in Expo Snack, where it is testable on both native and on web: https://snack.expo.dev/@alex-mclean/react-native-nested-pressables
As you can see in the Snack, the web implementation differs from the native implementations. The native implementations still allow for the inner pressable to be pressed when the outer pressable is disabled.
@necolas to your point from above
I'm not sure why the contents of a disabled element would be expected to be interactive
I do agree that this is maybe up for debate as a general pattern, however I don't think that providing behaviour on the web that differs from native is expected from this library.
I have resorted to patch-package to essentially revert https://github.com/necolas/react-native-web/commit/094bd0efc5ac1c566a81dec7ee825deae2c5a9a7 until this issue can be resolved.
We're running into the same thing since upgrading to [email protected]. While the behavior may be debatable, it's definitely a change (regression) and is not consistent with how the native counterparts (iOS/Android) treat these situations.
I also ran into the same issue. The behavior differed from the mobile versions, where the expected behavior is if the parent pressable was disabled, the children were still interactable. I patched the pointerEvents property on Pressable, TouchableOpacity, and TouchableHighlight to be 'box-none' when disabled instead.
Here's a copy of the patch:
diff --git a/node_modules/react-native-web/dist/exports/Pressable/index.js b/node_modules/react-native-web/dist/exports/Pressable/index.js
index 6212f1c..43af3f1 100644
--- a/node_modules/react-native-web/dist/exports/Pressable/index.js
+++ b/node_modules/react-native-web/dist/exports/Pressable/index.js
@@ -130,7 +130,7 @@ function Pressable(props, forwardedRef) {
onContextMenu: contextMenuHandler,
onFocus: focusHandler,
onKeyDown: keyDownHandler,
- pointerEvents: disabled ? 'none' : rest.pointerEvents,
+ pointerEvents: disabled ? 'box-none' : rest.pointerEvents,
ref: setRef,
style: [!disabled && styles.root, typeof style === 'function' ? style(interactionState) : style]
}), typeof children === 'function' ? children(interactionState) : children);
diff --git a/node_modules/react-native-web/dist/exports/TouchableHighlight/index.js b/node_modules/react-native-web/dist/exports/TouchableHighlight/index.js
index d40d223..ebb1176 100644
--- a/node_modules/react-native-web/dist/exports/TouchableHighlight/index.js
+++ b/node_modules/react-native-web/dist/exports/TouchableHighlight/index.js
@@ -130,7 +130,7 @@ function TouchableHighlight(props, forwardedRef) {
return /*#__PURE__*/React.createElement(View, _extends({}, rest, pressEventHandlers, {
accessibilityDisabled: disabled,
focusable: !disabled && focusable !== false,
- pointerEvents: disabled ? 'none' : undefined,
+ pointerEvents: disabled ? 'box-none' : undefined,
ref: setRef,
style: [styles.root, style, !disabled && styles.actionable, extraStyles && extraStyles.underlay]
}), /*#__PURE__*/React.cloneElement(child, {
diff --git a/node_modules/react-native-web/dist/exports/TouchableOpacity/index.js b/node_modules/react-native-web/dist/exports/TouchableOpacity/index.js
index 7000a93..9a2a6ff 100644
--- a/node_modules/react-native-web/dist/exports/TouchableOpacity/index.js
+++ b/node_modules/react-native-web/dist/exports/TouchableOpacity/index.js
@@ -90,7 +90,7 @@ function TouchableOpacity(props, forwardedRef) {
return /*#__PURE__*/React.createElement(View, _extends({}, rest, pressEventHandlers, {
accessibilityDisabled: disabled,
focusable: !disabled && focusable !== false,
- pointerEvents: disabled ? 'none' : undefined,
+ pointerEvents: disabled ? 'box-none' : undefined,
ref: setRef,
style: [styles.root, !disabled && styles.actionable, style, opacityOverride != null && {
opacity: opacityOverride
diff --git a/node_modules/react-native-web/src/exports/Pressable/index.js b/node_modules/react-native-web/src/exports/Pressable/index.js
index 5562e14..0798fa2 100644
--- a/node_modules/react-native-web/src/exports/Pressable/index.js
+++ b/node_modules/react-native-web/src/exports/Pressable/index.js
@@ -200,7 +200,7 @@ function Pressable(props: Props, forwardedRef): React.Node {
onContextMenu={contextMenuHandler}
onFocus={focusHandler}
onKeyDown={keyDownHandler}
- pointerEvents={disabled ? 'none' : rest.pointerEvents}
+ pointerEvents={disabled ? 'box-none' : rest.pointerEvents}
ref={setRef}
style={[
!disabled && styles.root,
diff --git a/node_modules/react-native-web/src/exports/TouchableHighlight/index.js b/node_modules/react-native-web/src/exports/TouchableHighlight/index.js
index eae524e..ad30ada 100644
--- a/node_modules/react-native-web/src/exports/TouchableHighlight/index.js
+++ b/node_modules/react-native-web/src/exports/TouchableHighlight/index.js
@@ -169,7 +169,7 @@ function TouchableHighlight(props: Props, forwardedRef): React.Node {
{...pressEventHandlers}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
- pointerEvents={disabled ? 'none' : undefined}
+ pointerEvents={disabled ? 'box-none' : undefined}
ref={setRef}
style={[
styles.root,
diff --git a/node_modules/react-native-web/src/exports/TouchableOpacity/index.js b/node_modules/react-native-web/src/exports/TouchableOpacity/index.js
index 5a7d624..dc1056a 100644
--- a/node_modules/react-native-web/src/exports/TouchableOpacity/index.js
+++ b/node_modules/react-native-web/src/exports/TouchableOpacity/index.js
@@ -126,7 +126,7 @@ function TouchableOpacity(props: Props, forwardedRef): React.Node {
{...pressEventHandlers}
accessibilityDisabled={disabled}
focusable={!disabled && focusable !== false}
- pointerEvents={disabled ? 'none' : undefined}
+ pointerEvents={disabled ? 'box-none' : undefined}
ref={setRef}
style={[
styles.root,