stripe-archive / react-stripe-elements

Moved to stripe/react-stripe-js.
https://github.com/stripe/react-stripe-js
MIT License
3.03k stars 319 forks source link

iOS Keyboard reopens with numberbad after loosing focus and closing keyboard #174

Closed faebeee closed 6 years ago

faebeee commented 6 years ago

Summary

The keyboard reopens automatically while clicking around.

iOS 11.2.1 Chrome 64.0.3282.112 Safari

Other information

Steps to reproduce: Can also be reproduced here: https://stripe.github.io/elements-examples/

  1. Click in the credit card number input field
  2. Fill in some numbers(Doesn't have to be valid or the complete number)
  3. Click outside the input box (Somewhere on the page, event if there is no elements there)
  4. Close keyboard with the Done or the X button
  5. Click somewhere and the keyboard reopens
sylver commented 6 years ago

Same problem here.

This isn't link to this repository and its components since I don't use them, I did my own wrapper around the stripe.js script. It seems something is keeping the focus once the card element got it. No way to get rid of it (blur() or unmount() function does not work, it keeps popping even if the parent component has been unmounted...

I confirm this is specific to Safari on iOS, I don't have the problem elsewhere.

I keep digging but some help from you guys would be great @michelle

Thanks

sylver commented 6 years ago

More investigation :

sylver commented 6 years ago

I found this problem is already discussed in #161 with a (kind of) workaround from @asolove-stripe I came to the same conclusion that the iframe with a different origin is messing up with the main app, and the fix should be in the Stripe.js script itself.

Why are you not fixing it ? This is basically making impossible to use your library on ALL iOS devices, it should be at least mentioned on the documentation page (https://stripe.com/docs/stripe-js) and in the readme of this repository. We should not have to dig in closed (unresolved) issues on github to eventually find something related.

EDIT: @asolove-stripe your workaround on #161 only takes into account the submit of the form. But the keyboard stays open in any other case (ie. when a blur occurs, no matter why).

I'm using something a bit more twisted (not really a fan, but at least it works in every case) :

// With element being a reference to the card element created by stripe.elements()
// or the CardElement component.
element.addEventListener('blur', ev => {
  // Apply only as a workaround for Safari on iOS,
  // else it will create an infinite loop on the `blur` event.
  if (navigator.userAgent.search("iPhone") != -1 &&
      navigator.userAgent.search("Version/" != -1)) {
    element.focus()
    element.blur()
  }

  // This is mandatory for all browsers
  element.getElementsByTagName("iframe")[0].blur()
}
michelle commented 6 years ago

Hi @sylv3r!

Thanks for the note, and sorry for the trouble this has been causing you. We're actively working on a fix internally and will post an update when it's out.

michelle commented 6 years ago

This should now be fixed! Let us know if you're still seeing issues.

afholderman commented 6 years ago

We're still seeing this issue. On version 1.6.0 the keyboard persists after the submit action and the app has moved to the next page.

cweiss-stripe commented 6 years ago

Hi @afholderman I can not reproduce the issue anymore. Could you provide some info on your integration (a code snippet or a link) and the device (iOS / Safari version) you are still seeing the issue with? Is it still broken for you on https://stripe.github.io/elements-examples/ ?

afholderman commented 6 years ago

@cweiss-stripe I was able to create a minimal repo and reproduce the issue on an ipad IOS 10.3.3. Once you click pay the keyboard will persist https://codesandbox.io/s/l72l6k779q

cweiss-stripe commented 6 years ago

Thank you @afholderman I can confirm that I am also seeing this issue with react-stripe-elements and split card* fields on Mobile Safari. (Heads up, that your codesandbox example is transitioning away before the token gets created, but after fixing this the keyboard behavior is still the same)

I'll reopen this PR and we'll post an update here once this is fixed.

cweiss-stripe commented 6 years ago

@afholderman thanks again for providing the details! This issue should be fixed now, you can check it e.g. here: https://codesandbox.io/s/5x09mrv58n Let me know if it works for you!

afholderman commented 6 years ago

@cweiss-stripe we have confirmed the fix in codesandbox and our application, thank you!

granmoe commented 6 years ago

I found this issue through a google search. I'm having a similar issue in our private codebase in an input that has some formatting logic. It turned out that our issue was happening because we update the cursor position of the input (using a ref) in componentDidUpdate, which for some reason causes a random focus event to fire only in iOS. My fix was to just track whether or not the input has focus (and this doesn't and probably shouldn't be part of component state since it doesn't change what gets rendered, just make it a class property or a plain variable in the component's module scope), and only run the cursor updating logic within the componentDidUpdate if hasFocus === true and the position needs to be updated.

Just thought I'd throw this in here in case it helps with your issue.

LeBenLeBen commented 6 years ago

Can somebody please provide more information about how this has been fixed? I have the same issue with vue-stripe-elements and Iā€™m not able to work around it using the information provided above.

davebalmer commented 6 years ago

Still an issue here, too. The keypad doesn't dismiss but worse is that even if the user dismisses it manually with "Done", it comes back later as they tap around. We're using elements directly -- no react or vue, etc.

jackhair commented 6 years ago

Same issue using ember-stripe-elements too.

cweiss-stripe commented 6 years ago

@granmoe Thanks for sharing your insights!

@LeBenLeBen @jackhair We fixed the issue in the underlying stripe-js, so it should be fixed for all wrapper libraries as well. Do you have an example page where I still can reproduce the issue?

@davebalmer Thanks for reporting this again. I can't reproduce it anymore on e.g. http://stripe.github.io/elements-examples/ Do you have a link to an example or a minimal reproduction where the problem still happens?

jackhair commented 6 years ago

@cweiss-stripe Thank you, can confirm this is fixed for us using the ember wrapper.

Which repo reflects the update for reference?

LeBenLeBen commented 6 years ago

@cweiss-stripe I can still reproduce the problem, but I think I narrowed the cause now. When I submit the form to get the token and then process the payment, I hide the Stripe Element and show a loader instead. In that specific case the bug happens. Here is a minimal reproduction case: https://codesandbox.io/s/0p8q30n30n (see App.vue file where every happens, except the Stripe JS file being included in index.html)

  1. Open the link above on an iOS device
  2. Fill-in the form with a test credit card (4242 4242 4242 4242)
  3. Submit => The keyboard stays open
  4. Close the keyboard manually with "Ok"
  5. Tap anywhere in the page, the keyboard opens

Could you please see if you can fix that case on your side as well or share any hints you would have to work around it? šŸ™‡

cweiss-stripe commented 6 years ago

@LeBenLeBen Thanks for the example! After submit, on Mobile Safari, the Stripe Card Element tries to close the keyboard by focusing and blurring a hidden input, which happens asynchronously and takes some time. In your case, you are removing the Element from the DOM on submit (with the if-directive that only renders the Element when loading === false), so the Element can't perform the steps to close the keyboard. There are a few ways to mitigate this by not removing the Element from the DOM. You could hide it via css or place an item on top of it. Please let me know if that works for you!

cweiss-stripe commented 6 years ago

@jackhair The change was made to the underlying Stripe.js library, which is not open source.

LeBenLeBen commented 6 years ago

@cweiss-stripe Actually I use v-show instead of v-if to hide the component from the page instead of removing it.

I tried to change the display: none (added by the v-show) to visibility: hidden but the result is the same. However if I use opacity: 0 the focus/blur happen and the keyboard is successfully hidden šŸŽ‰

I think I have enough information to work around it now, thanks for your help!

alexander-v-ysbm commented 6 years ago

Hi to All, I thing you get the separate problem to my, at iOS, maybe somebody can help me with stripe elements, I have use vue-stripe-elemetns and stripe-client packages but still get this on iPhone Safari. When I focus one of element it become to send requests to get some gif from stripe server, but real phone just freezing down. https://drive.google.com/file/d/13zxxwjFw4LKbEGumPRrbgczpMY59L8j2/view?usp=sharing

@cweiss-stripe

binomialstew commented 6 years ago

@alexander-v-ysbm, I'm seeing the same issue but using the current version of stripe.js directly with no wrapper. Using element.focus() is causing an infinite loop of alternating blur/focus GET requests to some gif on q.stripe.com, like you said. This effectively locks the site. I don't really understand why this is trying to get a gif, but it is sending elements.event.focus and elements.event.blur repeatedly as the event parameter for these requests.

asolove-stripe commented 6 years ago

@binomialstew Yikes, that doesn't sound good! I'm looking at our logs and can't seem to find an instance of this happening. I also tried several things in our test pages and couldn't make this happen. Do you have a url or a set of steps that can reliably reproduce it?

binomialstew commented 6 years ago

@asolove-stripe, thanks for reaching out.

I just looked at this again and realize it was my fault. I'm using a setOutcome() function both on element change and form submit that uses the element.focus() method, like this example. When I remove the function on change, there is no infinite loop. It seems there is a change event in iOS on submit that is not triggered in desktop browsers.

mmm111mmm commented 5 years ago

Are you all using Firefox on iOS by any chance?

I just had this issue: I would click on an input box, then click 'x' or 'done' on the keyboard, and then whenever I clicked anywhere else the keyboard would pop back up.

The code that simulated it is here

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
  </head>
  <body>
    <div>
      <input value="hiya">
    </div>
    <div>Sup with you???</div>
  </body>

</html>

It does not happen on Safari or Chrome.