1 of 21

JS Input Masking 🎭

Thomas Steiner, Google�tomac@google.com or @tomayac

Slides: https://goo.gle/ecma-402-js-input-masking

2 of 21

Input masks are everywhere.

3 of 21

Some of them unintuitive.

4 of 21

Some of them unintuitive.

5 of 21

Some of them unintuitive.

6 of 21

Some of them surprising.

7 of 21

Some of them surprising.

8 of 21

Some of them surprising.

9 of 21

Some of them actually helpful.

10 of 21

Some of them actually helpful.

11 of 21

There are client-side solutions to this.

Full-size screenshot of 15 JavaScript Input Mask Libraries (https://bashooka.com/coding/javascript-input-mask-libraries/)

12 of 21

A lot actually.

Full-size screenshot of a search on npm for “input-mask” (https://www.npmjs.com/search?q=keywords:input-mask)

13 of 21

There are a number of Intl.* formatters already…

14 of 21

What if there was an Intl.InputMask formatter?

// 16 digits.

new Intl.InputMask("credit-card-number")� .format("4012888888881881");

// "4012 8888 8888 1881"

// 15 digits.

new Intl.InputMask("credit-card-number")� .format("378282246310005");

// "3782 822463 10005"

Credit card numbers

15 of 21

What if there was an Intl.InputMask formatter?

new Intl.InputMask("phone-number", {

locale: "DE"

}).format("00494012345678");

// "00 49 40 12345678"

Phone numbers

16 of 21

What if there was an Intl.InputMask formatter?

new Intl.InputMask("international-bank-account-number")

.format("de04200411330524962800");

// "DE04 2004 1133 0524 9628 00"

IBAN numbers

17 of 21

What if there was an Intl.InputMask formatter?

// Custom "dashed" phone number formatter based on

// `Intl.InputMask("phone-number")`.

new Intl.InputMask("custom", {

maskFunction: (input) => {� return new Intl.InputMask("phone-number", {

locale: "DE"

}).format(input).replaceAll(" ", "-");� }

}).format("00494012345678");

// "00-49-40-12345678"

Custom formatter

18 of 21

Started working on a polyfill.

19 of 21

How would code using this look like in practice?

creditCardInput.addEventListener('input', (e) => {

if (e.inputType === 'deleteContentBackward') {

e.target.value = e.target.value.trim();

return;

}

// Save the caret position.

let caretPos = creditCardInput.selectionStart;

const value = e.target.value;

// Apply the input masking.

e.target.value = new Intl.InputMask('credit-card-number').format(

e.target.value,

);

// Restore the caret position while neutralizing the masking.

if (value !== e.target.value) {

caretPos += e.target.value.length - value.length;

}

creditCardInput.selectionStart = caretPos;

creditCardInput.selectionEnd = caretPos;

});

20 of 21

Open questions

Where to draw the line? ISBN numbers, telephone numbers, IBANs, credit card numbers,… Someone suggested IPv6 formatting.��Should this just be left to the client side? There is a solid ecosystem of input masking libraries, but the introductory examples have shown that it’s still hard.�

Iff you all think this should happen, what’re the next steps? Right now I have an explainer (https://github.com/tomayac/js-input-masking), a “try before you buy” polyfill (https://github.com/tomayac/js-input-masking-polyfill/), and a TC39 idea (https://es.discourse.group/t/input-masking/835). What’s next?

21 of 21

JS Input Masking 🎭

Thomas Steiner, Google�tomac@google.com or @tomayac

Slides: https://goo.gle/ecma-402-js-input-masking