57

In Mobile Safari I am unable to focus onto a text field after setting a delay period. I'm attaching some example code showcasing the issue. If, onclick of the button, you trigger .focus(), everything works as expected. If you hang the focus on a callback, like the setTimeout function, then it fails ONLY in mobile safari. In all other browsers, there is a delay, then the focus occurs.

Confusingly, the "focusin" event is triggered, even in mobile safari. This (and ~similar~ comments in SO) make me think that it's a mobile safari bug. Any guidance will be accepted.

I've tested in the emulator, and on iPhone 3GS/4 iOS4.

Example HTML:

<!DOCTYPE html> 
  <html lang='en'> 
    <head> 
      <title>Autofocus tests</title> 
      <meta content='width=device-width, initial-scale=1.0, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0' name='viewport'> 
      <meta content='yes' name='apple-mobile-web-app-capable'> 
    </head> 
    <body>
      <h1> 
        Show keyboard without user focus and select text:
      </h1> 
      <p> 
        <button id='focus-test-button'> 
          Should focus on input when you click me after .5 second
        </button> 
        <input id='focus-test-input' type='number' value='20'> 
      </p> 
      <script type="text/javascript"> 
        //<![CDATA[
        var button = document.getElementById('focus-test-button');
        var input  = document.getElementById('focus-test-input');

        input.addEventListener('focusin', function(event) {
          console.log('focus');
          console.log(event);
        });

        button.addEventListener('click', function() {
          // *** If triggered immediately - functionality occurs as expected
          // input.focus();
          // *** If called by callback - triggers the focusin event, but does not bring up keyboard or cursor
          var t = setTimeout("input.focus();",500);
        });
        //]]>
      </script>
    </body>
  </html>

~Similar~ SO questions:

Community
  • 1
  • 1
boymc
  • 1,217
  • 2
  • 13
  • 17
  • Mobile Safari has some focus problems. For example, you can't apply focus to a field via an onload event of the body. I'm guessing this is also a bug. – DA. Jun 09 '11 at 02:47
  • @DA I'm also starting to think that this is indeed in there with the focus() issues that are floating around in Mobile Safari. – boymc Jun 09 '11 at 03:55

6 Answers6

84

I think this is a feature of mobile Safari rather than a bug. In our work on FastClick, my colleagues and I found that iOS will only allow focus to be triggered on other elements, from within a function, if the first function in the call stack was triggered by a non-programmatic event. In your case, the call to setTimeout starts a new call stack, and the security mechanism kicks in to prevent you from setting focus on the input.

Remember that on iOS setting focus on an input element brings up the keyboard - so all those web pages out there that set focus on an input element on page load, like Google does, would be extremely annoying to use on iOS. I guess Apple decided they had to do something to prevent this. So I disagree with @DA: this is a feature not a bug.

There's no known workaround for this, so you'll have to ditch the idea of using a delay.

Update August 2012:

As of iOS 5, handlers triggered by synthesised click events are allowed to trigger focus on input elements. Try the updated FastClick input focus example.

Matthew
  • 15,464
  • 2
  • 37
  • 31
  • Thanks Matt. A really clear description of the issue. Idea was ditched. As you stated, probably for the best. – boymc Jan 03 '12 at 22:47
  • 1
    "autofocus" is an HTML5 attribute and Safari Mobile, Firefox 3.6 & IE9 don't support it. (I understand older browsers not supporting it... but iOS?) http://wufoo.com/html5/attributes/02-autofocus.html Whether it's a Apple/Safari "feature" or not, I'd prefer that it support the spec versus not function at all. I'm using a Bluetooth scanner and any scan requires an additional user interaction to click either on a text field or a button that sets the focus to a field. – James Moberg Apr 03 '12 at 16:59
  • 1
    Matt does your update on August 2012 mean we can trigger focus on input element from setTimeout event? – inlokesh Aug 20 '12 at 20:47
  • How do we synthesize a click event? – Joshua Oct 14 '12 at 17:15
  • 1
    [document.createEvent](https://developer.mozilla.org/en-US/docs/DOM/document.createEvent) – Matthew Oct 22 '12 at 22:58
  • Note however that the linked example wouldn't work with FastClick 0.6.1, probably because the call to sendClick is placed into a setTimeout callback. – Attila Kun Mar 07 '13 at 17:33
  • Thanks @kahoon. I'ved issue [82](https://github.com/ftlabs/fastclick/issues/82) on FastClick. – Matthew Mar 07 '13 at 19:22
  • 21
    Just wanted to add, that the whole behavior is due to this property of the UIWebView control: http://developer.apple.com/library/ios/#documentation/uikit/reference/UIWebView_Class/Reference/Reference.html#//apple_ref/occ/instp/UIWebView/keyboardDisplayRequiresUserAction In Safari it is set to 'YES', in Homescreen Webapps it is 'NO' and if you implement the control in your own app it is up to you. – Ronny Heuschkel Jul 16 '13 at 08:08
  • 10
    @RonnyHeuschkel Thank you! We are implementing a PhoneGap app, and we just inserted the following code in our `(void)webViewDidFinishLoad:(UIWebView*)theWebView` method: `theWebView.keyboardDisplayRequiresUserAction = NO;` Works like a charm! – Eric Galluzzo Jul 18 '13 at 14:50
  • @Matt - per your August 2012 update: the code in your FastClick input focus example still has a touchend event at root. Running the same code (in iOS7) from the console fails to trigger a focus. Are you able to trigger a focus from the command line or from a setTimeout? If so, any chance you could elaborate on how? It would help me and (it sounds like) a few dozen other people out immensely. Thanks - Dave – Dave Jan 29 '14 at 18:13
  • @Matt: nitpick, but triggering programmatic events calls event handlers synchronously, and can focus things fine, the problem demonstrated in your example page is that (in Safari on iOS < 5) `touchend` event handlers just can't focus things. Here's a page with more discriminatory test cases: http://jsbin.com/gixaduni/2 – Han Seoul-Oh Mar 27 '14 at 00:53
  • Agreed with @bendytree, is there a simple code sample for this? I'm looking for a text box to get focus on page load in Safari Mobile, and it appears it can be done? Can't decipher how from what's already here... – kyle_13 Mar 02 '15 at 15:36
  • 1
    This is not a very robust form of prevention if you ask me. In my site where opening a dropdown autofocuses an input inside of it, it brings up the keyboard automatically since opening the dropdown was triggered by a tap. I would much rather they made `.focus()` go ahead and focus the input without opening the keyboard, and make a user tap the only way to open the keyboard. – Andy Jul 08 '15 at 22:01
  • I tried your `FastClick` in iOS9.1, seems it doesn't work. I'm testing this on my iPad with iOS 9.1 – Giri Nov 18 '15 at 19:12
  • Enabling the preference "KeyboardDisplayRequiresUserAction" in my Cordova app (config.xml) solved the issue. Thanks a lot @RonnyHeuschkel – VinceOPS Jun 03 '16 at 16:57
6

I was able to raise the keyboard by dispatching a click event only when the original event was from user interaction, not from setTimeout. I believe the outcome is that you can raise the keyboard from a touchend event, but still not from a timeout.

Nick Saretzky
  • 61
  • 1
  • 1
  • 1
    How can you raise the keyboard on a keyboard event? Sounds weird, but I am seeing my keyboard go away when I process a keyboard event in such a way to bring a new text field to focus... – Michael Nov 30 '13 at 01:04
  • He meant that you can raise the "soft keyboard" or "keypad" from the phone using a touchend event, not raising the real keyboard. – Leo Aug 11 '23 at 14:41
2

It seems that focus() works only, if you have added the site to the home screen and has opened the site with this link.

elweilando
  • 182
  • 9
  • For me, focus() works if it is run as a web app from the home screen. – jakob.j Apr 23 '14 at 16:34
  • see comment http://stackoverflow.com/questions/6287478/mobile-safari-autofocus-text-field#comment25839502_7332160 in this page for how that works – Maarten Nov 18 '14 at 08:37
0

Adding to Matt answer. At least on Safari on iOS 5.1, this issue is fixed. Your FastClick works, that is, synthesizing a click event won't fail focus. However this does not help people who want their single focus() code to work on all iOS versions, sigh.

Himanshu
  • 31,810
  • 31
  • 111
  • 133
dodysw
  • 136
  • 2
  • 6
0

I was capable of making .focus() work by attaching it to two separate events in the events map but it's kind of hacky.

After adding FastClick.js, this is what happens in iOS: .focus() only works when its activated by a function that is attached to an event. BUT focus is also an event in mobile safari's event map that is actually called when you use jQuery's .focus(). SO you can be redundant and attach another .focus() on the focus event of the object to make certain that it pulls through. This works especially well when you're creating an input in the DOM. I like programming for MeteorJS lately, this is what the solution looks like there:

Template.templateName.events({
    "click button":function(){
        Session.set("makeButtonVisible",true);
        $("input.created").focus();
    },
    "focus input.created":function(){
        $("input.created").focus();
    }
});

Hopefully this is useful to someone out there, took me like two hours to figure this one out.

EDIT: Well, for MeteorJS in particular, you can't use Template.templateName.rendered function either because the .focus() must be invoked from an event. BUT for some reason when you add an input through jQuery you can focus on it inside the event. Guess that's the way to go. This is what I ended up doing:

Template.templateName.events({
    "click button":function(){
        $("body").append("<input class='created' type='tel'>");
        $("input.created").focus();
    }
});
Marz
  • 381
  • 5
  • 10
  • 2
    Bah, crap, nvm. It worked on accident because I added other events that made the function run twice. The solution is somewhere around there though. – Marz Sep 08 '13 at 06:53
-10

You answered yourself. You need just trigger if you use Jquery. Change focus() on trigger("focus"); in any part of your code.

$("#searchField").trigger("focus");

Dimash
  • 581
  • 1
  • 5
  • 13