Maintaining Focus

Andy Weiss
RBI Tech
Published in
5 min readFeb 28, 2021

Keeping Form Elements Visible in Hybrid iOS Apps

Today’s mobile browsers provide a pretty great default user experience for forms. For a very simple example, visit the following url from any mobile browser: https://VisualViewport.andyweiss1982.repl.co.

The user experience is great from mobile Safari.

When you focus on an input field, the phone’s soft keyboard animates up from the bottom of the screen. All of the content comes along for the ride, intelligently sliding up so you can see each input’s value as you type. Close out the form and the viewport gracefully recedes from view.

However, the same exact code can become far less elegant when consumed from a web view inside of a hybrid iOS app.

Not so great inside of an iOS web view

Not only do we lose the “Done” button that closes the keyboard without submitting the form; in many cases, the keyboard will pop up without displacing the form elements, covering them entirely and making the form appear completely useless!

Well, It works in my web browser? 🤷‍♂️

For reference, here is the full code for the original user experience as viewed from the mobile web:

To move this code inside of a web view, we can use Ionic’s capacitor package to generate a bare-bones hybrid app that can be run in a simulator. Following the docs, you can create a new project, give it a name and assign it a directory, and then add the Android and iOS platforms.

npx @capacitor/cli create? App name hybrid-forms-test
? App Package ID (in Java package format, no dashes) com.example.app
? Directory for new app hybrid-forms-test
? Which npm client would you like to use? yarn
Add platforms using "npx cap add":npx cap add android
npx cap add ios

For the purposes of this demo, you can just copy and paste the following code into www/index.html to generate a carbon copy of the original example into a boilerplate capacitor web view that can be run as either an iOS or Android application:

Assuming you already have Xcode and Android Studio installed, you can run the project in either platform’s simulator with the following commands:

npx cap sync ios && npx cap open ios
npx cap sync android && npx cap open android

You can see the Android version seems to deliver an experience more faithful to a mobile web browser, so anything we do to improve the interaction for iOS needs to leave the Android experience untouched.

The keyboard correctly displaces form elements in an Android web view

Luckily, capacitor gives us access to a keyboard API that we can use to customize its behavior inside of the web view.

Addition by subtraction ✂️

Our first item of business is to disable the iOS keyboard’s default resizing behavior, as it clearly isn’t doing what we want. Inside of capacitor.config.json , you can add an entry to the “plugins” object that set’s the keyboard’s resize key to “none” —and according to the documentation, this only affects behavior in iOS.

"plugins": {
"Keyboard": {
"resize": "none"
},
// more plugins...
}

Next, let’s try to implement an interaction closer to what we are looking for: the overall effect we are after is to slide the viewport up, and ensure the focused form element is visible.

One fairly straightforward way to accomplish this is by applying a y-axis translation to the body element equal to the height of the keyboard, and then using the Element.scrollIntoViewIfNeeded API on the document’s activeElement. scrollIntoViewIfNeeded is flagged as non-standard, but appears to be well supported inside the iOS web view’s browser. Capacitor exposes an API for us to listen for show and hide events on the soft keyboard, so we can apply and remove these effects at just the right moment.

Finally, we can add back in the “Done” button, which will allow the user to hide the keyboard without submitting the form. This is achieved by setting the accessory bar visible.

We can see this all come together by adding a simple script tag at the very bottom of the body in www/index.html. You can certainly incorporate something similar into a hook for React or your preferred frontend framework, but this demonstrates the basic idea nicely. Don’t forget, we want to leave the Android experience unchanged, so let’s be sure to only run this code on particular devices.

The big reveal 🪄

To update the web view in each platform’s simulator, simply run the following command and before generating a new build in Xcode and Android Studio.

npx cap copy

The iOS app should now exhibit behavior much closer to that of the mobile web, and the Android app should behave the same as before. Overall this is a major improvement over our initial user experience, with minimal additional code.

The form elements are now always visible and centered on both platforms.

Other ways to achieve a similar effect might rely on the Visual Viewport API, or on alternate CSS transformations. If you’ve solved this problem with a different approach, I’d love to hear from you!

Restaurant Brands International is Hiring 🍔 🍗 ☕️

See our open roles in the United States, Latin America, Canada, and Europe.

Still in school? Check out out our internship opportunities!

--

--