{{autofocus}} modifier: improving our component APIs

While building an autofocus feature for our components, we have been able to improve their APIs. Let’s see how we achieved that with the {{autofocus}} modifier.

Cyrille David
Dec 13, 2019 · 3 min read
Image for post
Image for post

Inviting a new admin on the company account, creating a new card, issuing a transfer. All these actions are sensitive and need to be confirmed by the user. To confirm them, we require a one-time-password to be filled from a text message. As a neobank, security is at the essence of what we do at Qonto, but we should not let it degrade the experience. This is why we want to autofocus this input.

autofocusing a component
autofocusing a component
In the following gif, see what it can look like from a user perspective.

Make the confirm action easier

Let’s automatically focus that one-time-password input. To provide the user with an indication and a starting point, so that they can easily confirm their action.

That is not the only use of such an autofocus behavior. In another one of our web apps, we prompt the user for an email address, with the goal of starting the registration process. The email input is the only relevant information on the page. In that case, we also want the input to be focused on display.

Our one-time-password input and our email input are both components. But they are not quite the same component.

This autofocus feature needs to be implemented in several components, spread across two apps. The question is: how do we share the code?

Moving towards better APIs for our components

One option would be to use a mixin, but mixins are no longer recommended in Ember ecosystem (1). Thankfully, we have a new feature in Ember for sharing code between components, similar to directives in Vue or Angular: Ember modifiers.

With a modifier, we can apply a modification to a DOM element with a function or a class. It allows us to use a component like this, notice the {{autofocus}} part:

<OTPInput
@label="Confirmation Code"
@value={{this.confirmationCode}}
{{on "update" this.updateCode}}
{{autofocus}}
/>

Modifiers are a feature planned for the next (and first!) Ember Edition (2). That feature is currently being experimented with in a third-party package: https://github.com/ember-modifier/ember-modifier.

If you want to go into the details about modifiers, you can look at this linked blog post.

Iteration #1

A simplified version of our modifier would be:

import { modifier } from 'ember-modifier';export default modifier(function autofocus(element) {
element.focus();
});

Simple.

Iteration #2

Let’s make this a bit more sophisticated, and autofocus the first non-disabled input — if it exists:

import { modifier } from 'ember-modifier';export default modifier(function autofocus(element) {
let childElement = element.querySelector('input:not([disabled])');
if (childElement) {
childElement.focus();
} else {
element.focus();
}
});

Iteration #3

Last iteration, let our modifier support taking a selector as a parameter:

<ConfirmationModal {{autofocus "#confirm-button"}}>

We’re taking advantage of the positional parameters here, that we can get in our modifier function as an array in the second parameter. Our autofocus modifier becomes like that:

import { modifier } from 'ember-modifier';export default modifier(function autofocus(element, [selector = 'input:not([disabled])']) {
let childElement = element.querySelector(selector);
if (childElement) {
childElement.focus();
} else {
element.focus();
}
});

And we can use it set the focus on an informative modal’s close button.

Conclusion: let’s use this code

The code is wrapped up in a small addon: ember-autofocus-modifier. You can use it as is. Or you could copy the code and experiment with creating you own modifier.

Thanks to this work, we can share code between multiple apps. We keep some implementations consistent while distributed.

To install the addon, run the command yarn add -D ember-autofocus-modifier (or npm install --save-dev ember-autofocus-modifier). Then, {{autofocus}} modifier is available in your templates.

Thanks for reading!

(1) on why Mixins are not a recommended pattern anymore: https://github.com/emberjs/rfcs/issues/534

(2) you don’t know what a Ember Edition is? https://emberjs.com/editions/

The Qonto Way

Learning while scaling

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store