Auto-scrolling to the first validation error on iOS (fixing a minor Forms 2.0 inconsistency)

Marketo Forms are based on a true HTML <form> tag, and use standard (semantic/non-fake) HTML <input> types whenever possible. As I always take care to say, this is A Very Good Thing™! Doing anything else is a disaster for usability and familiarity, especially on mobile.

A consequence of bog-standard markup, of course, is built-in “special effects” featured in one browser might not be supported in another. And that happens even if the effect is in the latest HTML5 standard and the browser is brand new!

Case in point: scrolling the focused element into view when focus() is called programmatically. Specifically, when the Marketo Forms 2.0 library detects a validation error on a field, it pops up the red error tooltip and focuses that field. On every browser but iOS Safari, the act of focusing also scrolls that field into view.

Check this replay of the everywhere-but-iOS behavior:

animated-ss

(Sorry about the recording quality, the conversion from MP4 → GIF was a little choppy.)

As you can see, First Name (which starts out offscreen) is required but empty. Clicking the Submit button not only brings up the error, it also scrolls up to show the field for the user to fill in.

Here’s what happens on iOS:

animated-ss

You can’t see it, but the red error did draw under First Name and that field does have the focus. Problem is, the field remains scrolled out of view! Hmm.

Standard behavior or merely traditional behavior?

Now, to be clear, the Forms 2.0 library didn’t do anything special on other platforms. It’s just that on those others, focus() also implies scrolling into view.

I was curious whether this was a formal standard and indeed in the cutting-edge HTML standard, it is:

ss

So the standard — itself derived from browser vendors’ historical, agreed, and proposed behavior, so bit of a chicken-egg situation — says “focus” means “focus and scroll” by default.

preventScroll (that is, focus({preventScroll : true}) is a non-default option to turn off the scroll.

Apple bucks the standard on iOS for whatever reason. Misguided idea of security/end-user control, perhaps. Or they just haven’t gotten to it.

In any case, we can fix it up.

The code

All we need is one of my best friends, a capturing event listener:

if (/^(iPad|iPhone|iPod)$/.test(navigator.platform)) {
   MktoForms2.whenReady(function (form) {
      var formEl = form.getFormElem()[0];
      
      formEl.addEventListener("focus",function(e){
            e.target.scrollIntoView();
      }, true)         
   });
}

Listen for focus, then chain that with the built-in method scrollIntoView to simulate the behavior in the standard.

P.S. The iOS platform detection is primitive, but AFAIK there’s no feature detection that’s better.

P.P.S. I made no attempt to bring up the mobile keyboard on focus + scroll. That would require a lot more code, and presumably once the person sees the offending field, they can handle the typing part!