5 Utilities
Liam DeBeasi edited this page 2021-09-28 13:38:50 -04:00

There are a number of utilities that help make Ionic Framework work better. If you are building with Ionic Framework, you should not need to worry about managing these utilities in your app. However, if you are trying to investigate a bug or make a contribution to Ionic Framework, it would be good to have a working knowledge of some of these utilities.

This guide will go over how each utility works and the role they play in making Ionic Framework function.

Focus Visible

The focus visible utility can be found at core/src/utils/focus-visible. This utility serves to add a visual focus indicator to elements that have been focused with the keyboard. Given a collection ion-item buttons in an ion-list, tabbing through the list will add a visual indicator to the currently focused item. So why do we use this utility instead of :focus? The main reason here is mobile. Tapping a button on mobile also focuses the button. So if we relied on :focus, then the visual focused indicator would remain on the button even after removing your finger from the screen. There is a :focus-visible CSS pseudo-class that can help us here, but it is not widely supported as of 2021. Eventually we will be able to rely on :focus-visible, but for now we use the focus-visible JavaScript utility.

There are two requirements to have an element participate in the focus-visible utility:

  1. The element needs the .ion-focusable class set.
  2. <ion-app> needs to be used on the page. This utility is automatically started when <ion-app> is used.

Alternatively, you can import startFocusVisible and start the utility yourself. This is useful if you need this utility to run inside of the Shadow DOM. See https://github.com/ionic-team/ionic-framework/blob/next/core/src/components/datetime/datetime.tsx#L794 for a usage example.

Tap Click

The tap click utility can be found at core/src/utils/tap-click and serves two purposes. The first purpose is to activate the ripple effect on Ionic components that use <ion-ripple-effect>. The second purpose is to add the .ion-activated class to Ionic components that have .ion-activatable. This gives the visual indication that a component is being pressed or clicked.

Normally, you could use the :active psuedo class to set an element's active state, but browser engines such as WebKit on iOS do not set the :active pseudo class (see: Apple Developer - Highlighting Elements). One way to work around this is to add an empty touchstart event listener to the component, but this would require us to add a touchstart event listener to each component, introducing a performance overhead. As of 2021, using touch-action does not resolve this issue either.

Since we already use tap click to add the ripple effect, we were able to create an "activated" behavior that is consistent across all browser engines without adding a significant performance overhead.

By default, the .ion-activated class is removed after a timeout. This is done to ensure that the activated indicator is visible enough for users to notice. The .ion-activatable-instant class can be added to elements to bypass this timeout.

Input Shims

Our input shims can be found at core/src/utils/input-shims. These shims are enabled inside of the ion-app component, meaning you need to use ion-app in order to have these utilities activate. The main entry point for these utilities can be found in the startInputShims function in core/src/utils/input-shims/input-shims.ts. Below lists all of the shims we use.

Hide Caret

When an input is focused, this utility will hide the caret when a user scrolls the page. Mobile browser engines such as WebKit have issues with the caret not scrolling with the input, so rather than have that visual glitch there we hide the caret while scrolling altogether. The reason this glitch happens is because on iOS the caret is not part of the webview, it is part of the operating system so it is does not know the scrolling position. Chromium used to have this issue, but the Chromium team has since fixed it.

Input Blurring

When tapping outside of an input, the input should blur and the keyboard should hide. However, that should not happen when the user attempts to scroll, otherwise the input would be blurred at the slightest of scroll gestures. This utility ensures that tapping outside of an input blurs the input, unless the user is scrolling.

Scroll Assist

A common pain point in mobile apps is the keyboard. Web APIs do not provide a great deal of control over the on screen keyboard, so an issue you will see frequently is the keyboard covering an input when tapping into it. Our scroll assist utility does its best to adjust the content scroll position so that the focused input is always shown above the keyboard. Because we do not always know the exact height of the keyboard, sometimes the content will be scrolled more than it needs.

Scroll Padding

Typically when the keyboard opens on Capacitor or Cordova, the webview will resize to 100% of the screen height minus the height of the keyboard. This gives scroll assist enough scrolling real estate to adjust the content scroll position so that the focused input shows above the keyboard. Developers are given the ability to disable this webview resizing. When that happens, scroll assist will not have enough scrolling real estate to adjust the content scroll position. The scroll padding utility accounts for this by adding padding-bottom to the scrollable content roughly equal to the height of the keyboard.