I am having issues with the blur event not firing consistently on iPhones. I am trying to show errors on blur events. The first blur event works and the error is shown but after that even on different fields the error will not show even if it should since after the first blur event the code does not detect/receive a blur event. However, fieldStateChange events fire consistently but I don't want to show errors while a user is typing.
Thank you for any and all help!
Thanks for reporting, @jpowell127.
There are some known issues with iOS Safari and how it handles blur and focus events across iframes. Many times we can detect that a focus or blur took place but the browser ignores our calls to manually transition focus.
The cause appears to be this:
Each iframe maintains its own notion what is focused _within_ itself, and is ignorant of its parent or sister frames' notion of what _they_ have focused. You will see the behavior that we may trigger a focus event properly the _first_ time an input is selected, but focusing elsewhere on the page and then re-focusing that same input does not fire any events within the iframe (as the iframe never though the input lost focus).
We try and intelligently maintain our state and force a blur in all other hosted fields when any single one receives focus. This works in most browsers, but seems to have limited effect in mobile Safari.
We are trying to work on some clever hacks to work around this limitation, but our options so far seem to be limited until proper event and focus handling is fixed in subsequent iOS Safari versions.
We also noticed a related issue:
I'm sorry to say that we don't have a workaround yet, but the issue is known to us.
Hi mrak,
I have a same problem, I have used beta.10 javascript SDK . When I open payment page on Iphone Safari, following problem occurs
Can you please give some idea , how can I solve this ?
@pratikpanchal123 Thanks for the report. We're working on it. Unfortunately, this is still the case:
We are trying to work on some clever hacks to work around this limitation, but our options so far seem to be limited until proper event and focus handling is fixed in subsequent iOS Safari versions.
@crookedneighbor I take it since there has been no response you guys have not had any luck fixing this issue? I am not sure if it is related, but I am seeing an issue where on iOS when the user selects a field and tries to type nothing happens. The keyboard appears and the cursor "looks" like it is in the field but when you type nothing appears. you have to close the keyboard and lose focus of the field and then tap it again and hopefully get lucky that you can type now.
If this is not related, please just let me know and I will gladly make a new issue with more details.
@NickMele Seems unrelated to me. Please open a new issue and state what version of braintree-web you are using.
@crookedneighbor Will do for sure.
I've very recently came across this and is royally blocking us from rolling out our new customised payment form using hosted fields.
I appreciate that this is an iOS bug, but there's a potential workaround. If you are happy with the following workaround I will create a new github issue.
Jumping between a hosted fields input to a non-hosted fields input breaks iOS focusing.
Jumping between hosted field to another hosted field however does not break.
See gif below:

A workaround would be to allow creating custom hosted fields. Passing the following to braintree hosted fields instance (v3 Javascript) could mean that we can create a custom field fields
{
client: client,
fields: {
number: {
selector: '#card-input-number'
},
cvv: {
selector: '#card-input-cvv'
},
expirationMonth: {
selector: '#card-input-expiration-month',
placeholder: 'MM'
},
expirationYear: {
selector: '#card-input-expiration-year',
placeholder: 'YYYY'
},
postalCode: {
selector: '#card-input-postal-code'
},
custom: {
firstName: { // Name of custom field for identifying it outside the braintree library
tokenizationKey: "billing.firstName", // Set the value of this input to that key when calling the `hostedFields.tokenize` method.
isValid: function(value) {
// Return logic for checking if value is valid
}
}
}
}
}
Thanks for the suggestion, @mschinis. If I understand correctly, you want to move your own inputs into hosted fields so that the focussing behavior is consistent between all of your form's inputs?
Unfortunately, do to PCI concerns we cannot allow external access to the input values on our domain as your isValid: function(value) suggests. We also cannot move function declarations across frame boundaries as it would involve the use of eval and be a possible attack vector.
Hello @mrak ,
Yes, moving the input into a hosted field is to keep the behaviour consistent.
PCI concerns, make sense. What if you ran basic validations on the custom fields and exposed booleans like isNumeric, isEmpty for the custom inputs? Further to above, the isValid and isPotentiallyValid functions could be replaced to be a combination of something like the following:
{
firstName: {
minLength: 3,
maxLength: 3
}
}
I understand that validations are outside of the scope of this library, but this would help developers run basic validations and make the library a lot more powerful and flexible.
Edit: react-jsonschema-form has a nice API for creating custom validations without the need to pass functions down to the component. https://github.com/mozilla-services/react-jsonschema-form#custom-validation
Adding custom fields may be a bit of a feature overkill only to work around focusing issues for a specific browser. The source of this issue needs a fix from Apple.
If you'd like custom fields support in hosted fields (separate from being related to this issue), feel free to open a new issue.
For those of you wanting to take action to get iOS iframe input focus behavior fixed, we encourage you to file bug reports directly to Apple. You can also post in their developer forum to voice your concerns on this issue.
version 3.8.0 has just been released, and we believe that the blur events will now fire correctly on iOS browsers.
Hi @mrak,
Do you know of any potential workaround for the original iOS bug here? Or is Braintree working to handle it inside of those hosted fields?
We're running v3.20 and are still facing this issue.
I've tried:
window.focus()). This does work when the input is rightly focussed (and my site does not have focus). But when my site does have focus (ie user taps away from input iframe causing real focus to land on my site) it should (but doesn't) force a blur on the iframe input.@nathanbirrell The original reported issue is that the hosted fields blur events were not firing consistently on iOS devices. Can you confirm that is the iOS bug you are referring to?
So this code:
hostedFieldsInstance.on('blur', function (event) {
console.log(event);
});
Would never console log. The changes made back in 3.8.0 should have fixed that and I cannot reproduce this issue using the latest version.
Can you provide what browser version you are using? Is it Safari? A webview? If a webview, is it a UI webview, a WK webview or a safari view controller?
Thank you @crookedneighbor. I think I was confused reading this thread. Yes the blur event does fire when attached to the _hosted fields instance_.
For anyone else interested:
The iOS keypad would not disappear on blur (because the event wasn't firing, as well documented above).
To force the keypad down, inside the hosted fields instance blur event, we've created a resetIOSKeyboard function to create an input, focus it, then destroy it. Effectively, this steals focus and forces the keypad away. 馃帀
For example:
hostedFieldsInstance.on('blur', function (event) {
let input = document.createElement('input');
input.setAttribute('type', 'text');
// Prepend to active element to ensure scroll lands somewhere relevant
document.activeElement.prepend(input);
input.focus();
input.parentNode.removeChild(input);
});
v3.20.1 has a similar fix for this very issue. See https://github.com/braintree/braintree-web/commit/c0eae9982ef206960341eb3d1c955f83de44587c#diff-612fb92fe5af31a25d988cc430c6debf
The one issue I see with your workaround is that if a user taps from one hosted fields input to another (or another input outside of hosted fields), the input will lose focus.
In our fix in 3.20.1, we first check that the device is an iOS device (as the bug does not occur elsewhere) and then we check that the active element is the document body before applying the workaround.
I encourage you to update to the latest version (3.22.2) and see if that solves the issue for you.
Awesome, thanks @crookedneighbor looks like that has worked 馃帀
@mrak This problem is happening on not just Safari but also Chrome for iOS mobile devices.
I am having this issue as well. It seems that any inputs within an iFrame the iOS mobile devices (any browser) does not recognize when that particular input looses focus.
To reproduce this error please go to: https://pantaya.com/billing/payment
create a dummy account and see on the payment page.
I created a question on Stackoverflow:
Situation:
Material Design Floating Labels are stuck with a class="in-focused" even when the input is out of focus. The inputs also contain an iFrame generated from Recurly if that helps.
This seems to happen on (Chrome and Safari) browsers for any iOS Mobile device (iPads iPhones any version). Also, the inputs are all iFrames. Sometimes the cursor will disappear (version 9 and below) when you try to tap back into an empty input field as an additional error. The iFrames are generated from Recurly.
I believe there is an issue with Mobile Safari devices where it doesn't recognize a possible Blur event.
Question:
My goal is to remove the class="is-focused" from any element that is not in focus. What would you you recommend as a solution for this problem?
If you would like to reproduce the error you can see if you go to this url: https://pantaya.com/billing/payment (sign up a dummy account if you need to...) You will see the form that gives these errors.
All advice is helpful! Thank you!
Under the hood, chrome for iOS is just a safari webview, so it's expected that the same buggy behavior exists.
I'd take a look at the various discussions in this issue, especially the last few comments, they provide some workarounds. Ultimately though, the problem is that Safari (and it's webviews) has a bug regrading focus and blurring elements within an iframe, and there's nothing we can really do about it.
@crookedneighbor did Apple ever fix the issue mention in the thread? or do we still need to use the hack to fix the issue?
To my knowledge, Apple still has not fixed this issue with inputs inside of iframes in iOS Safari.
@crookedneighbor Thanks for prompt reply. I see you guys are using blur event listener to workaround the issue.
I don't see blur event fired when i click on any element outside iframe. Do you have any suggestions? Also weird thing is i am only seeing this issue on ios 11.4.
What other versions are you testing on that are not experiencing the issue?
I have tested this on ios 11.1,11.2, also i tried on ios 10.X. I am seeing this issue outside braintree web environment. I need a fix there.
Any news on this subject ?
To my knowledge, Apple still has not fixed the underlying bug in Safari.
I have same issue, any update for this?
Same answer as before, Apple has not fixed the underlying bug in Safari.
just like you know, we changed the above hacky code in our project for forcing blurand it's working for us now:
function forceBlur(parent) {
let input = document.createElement('input');
input.setAttribute('type', 'text');
parent.insertBefore(input, parent.firstChild);
input.focus();
parent.removeChild(input);
}
parent is our form here.
Most helpful comment
I've very recently came across this and is royally blocking us from rolling out our new customised payment form using hosted fields.
I appreciate that this is an iOS bug, but there's a potential workaround. If you are happy with the following workaround I will create a new github issue.
Problem
Jumping between a hosted fields input to a non-hosted fields input breaks iOS focusing.

Jumping between hosted field to another hosted field however does not break.
See gif below:
Potential solution
A workaround would be to allow creating custom hosted fields. Passing the following to braintree hosted fields instance (v3 Javascript) could mean that we can create a custom field fields