iOS Safari 10 address autofill

Why does the iOS Safari 10 address autofill not work well with autocomplete?

In an HTML form with a text input element for an address, you may find that Safari on iOS 10 automatically prompts the user to enter one of the addresses from their contact info, without needing the user to enter a single letter.  After tapping on one of the addresses, Safari fills the field with the address, and Safari seems to assume the user will not enter any more text into this field, and then removes the focus from the input field.  This prevents autocompleters from displaying completions as it appears the user has lost focus.

To replicate this, you need a contact in iOS 10 for yourself, with an address set:

ios contact with work address
ios contact with work address

You’ll also need to tell iOS that this is you (search Settings for “My Info”):

My Info in iOS Settings
My Info in iOS Settings

Now when you focus on an address text input field in Safari, it’ll suggest autofill with your contact address(es):

autofill address suggestion
autofill address suggestion

If you tap on the address, you’ll see that your address is autofilled without you needing to enter another single thing.  Unfortunately, on our site, you need to select an address from the autocomplete list in order for it to work.

If you connect desktop Safari’s Web Inspector, record a Timeline, and look at the JavaScript & Events, you’ll see that the input event is being triggered. So why isn’t the autocomplete showing? We couldn’t find any information on the web about it (maybe we’re using the wrong keywords), so we set about diagnosing and working around it ourselves.

We use two autocompleters on our site (at the moment): jQuery UI 1.10’s widget and Awesomplete. jQuery UI wouldn’t trigger the source function, even if we set delay to 0 and when the list is ready.  Awesomplete checks that the the text input element is still active (in focus). If the list was ready synchronously with the input event, then Awesomplete might show it, but we prepare the list asynchronously, so by the time we give it to Awesomplete, Safari has already taken away the focus (blur event).

Our fix for jQuery UI was two-fold:

  1. force the search when the input event is triggered:
    $addressInput.on('input', function () {
      $addressInput.autocomplete('search', this.value);
    });
    
  2. override the response so the search is is un-cancelled:
     $.widget('custom.autocomplete', $.ui.autocomplete, {
      __response: function(content) {
        this.cancelSearch = false;
        return this._super(content);
      }
    });
    

Our fix for Awesomplete was a little more intrusive, to comment out the check that the input element is still active (yes, we know we can just call evaluate after setting the list):

// if (document.activeElement === this.input) {
   this.evaluate();
// }

So now, if the user appears to have lost focus (either because they have, or because Safari blurs the field), the autocomplete will still display:

autofilled address with autocomplete
autofilled address with autocomplete