Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't press and hold a Pressable on Android web #2349

Closed
1 task done
elliotwaite opened this issue Jul 21, 2022 · 6 comments
Closed
1 task done

Can't press and hold a Pressable on Android web #2349

elliotwaite opened this issue Jul 21, 2022 · 6 comments
Labels

Comments

@elliotwaite
Copy link

Is there an existing issue for this?

  • I have searched the existing issues

Describe the issue

On Android web, when you press and hold a Pressable, it automatically calls its onPressOut callback after only a short delay, even if the Pressable is still being pressed, making it impossible to press and hold a Pressable for an extended amount of time.

Expected behavior

I expected the Pressable to call its onPressOut callback only after it is no longer being pressed.

Steps to reproduce

  1. Load this Snack in a browser on an Android phone (I tested it using both Chrome and Firefox):
    https://snack.expo.dev/@elliotwaite/press-and-hold-test
  2. Load the desktop version of the site if needed to be able to interact with the web preview.
  3. Try to press and hold the button.

Test case

https://snack.expo.dev/@elliotwaite/press-and-hold-test

Additional comments

Here's an animated gif of a recording of what happens:
press-and-hold-demo

I wasn't sure if this was an issue with react-native-web or something else. So let me know if there would be a better place for me to open an issue about this.

@necolas
Copy link
Owner

necolas commented Jul 22, 2022

I think what's happening is that you are long-touching, and that triggers a contextmenu event which ends the press. I don't know why the native contextmenu UI is not being displayed though (shows up in Chrome's mobile emulator). If you want to own the long-touch behavior, set the onLongPress handler, which will automatically prevent the contextmenu and native press-cancelling behavior.

https://codesandbox.io/s/clever-herschel-2z09xj?file=/src/App.js

This does get me wondering a bit about the relationship between contextmenu and longpress events.

A touch-type longpress is usually a way to display secondary features, conceptually very similar to contextmenu. Browsers automatically dispatch the contextmenu PointerEvent, and cancel the pointer, when a touch pointer is held down and not moved for a set amount of time. So longpress necessarily must handle contextmenu and appears to be essentially the same as contextmenu handler calling preventDefault() if pointerType === 'touch'. It's not typical to find longpress-like behaviors when using a mouse or keyboard. And as with touch, custom secondary menus must prevent the native contextmenu. So contextmenu is common to all modality types as a way of signaling user intent to use secondary menus/features. And the concept of longpress seems specific to touch/pen interactions with screens.

@elliotwaite
Copy link
Author

Got it. Thanks for the solution and the explanation. And that's an interesting observation about the relationship between contextmenu and longpress.

I noticed that after adding onLongPress={() => {}} I'm now getting a short haptic feedback event when the onLongPress event fires (on Chrome at least). It's similar to the haptic feedback that occurs when a long press is used to open a context menu. Do you know if it's possible to disable this haptic feedback? Disabling it outside of React has been discussed a bit here, but I wasn't sure how to translate their solution to work with Pressable.

@necolas
Copy link
Owner

necolas commented Jul 25, 2022

You should be able to set both those CSS properties on your pressable element.

@elliotwaite
Copy link
Author

I've tried setting the CSS properties that were mentioned in that StackOverflow discussion, but they didn't seem to remove the haptic feedback (demo).

It was more the e.preventDefault() and e.stopPropagation() for the touchstart and touchend events (as mentioned in this answer) that I didn't know how to translate over to using with Pressable. I tried adding e.preventDefault() and e.stopPropagation() to onPress, onPressIn, onPressOut, and onLongPress (demo), but those changes didn't seem to remove the haptic feedback either.

Do you have any other suggestions for things I could try?

@necolas
Copy link
Owner

necolas commented Jul 26, 2022

No other suggestions. Until now I wasn't aware that browsers didn't cancel the haptic feedback along with the rest of the default behaviour.

The pressable callbacks are built on the responder system abstraction, which depends on touch events but doesn't alter their propagation or expose them for further modification. Having said that, it sounds like this might be an issue that we could/should fix somewhere in this chain of abstractions rather than in your product code.

@elliotwaite
Copy link
Author

elliotwaite commented Jul 26, 2022

Okay, got it. Since your suggestion of adding onLongPress={() => {}} resolved the original issue, I'm going to close this issue, and I opened a new issue that focuses on the haptic feedback issue: #2352

Thanks again for helping me resolve the original issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants