2

I am trying to write a custom Lightning Web Component that displays a single lightning-input text component and dynamically masks the input as the user enters it. By "masks" I mean it reformats the user's input as the user types.

For example, the user could type the 9 digits of a U.S. Social Security number and the mask would automatically insert the dashes in the correct places.

I have attempted to do this using third-party JavaScript libraries in two different ways:

  1. Uploaded as a static resource and loaded into the component via loadScript().

  2. Including the third-party library as its own Lightning Web Component and importing it.

In both cases I tried to apply the input mask to the input field inside the renderedCallback hook.

import { loadScript } from 'lightning/platformResourceLoader';
import vanillaTextMask from '@salesforce/resourceurl/vanillaTextMask';

async renderedCallback() {
  await loadScript(this, vanillaTextMask);
  const input = this.template.querySelector('lightning-input');
  vanillaTextMask.maskInput({
    inputElement: input,
    mask: [/\d/, /\d/, /\d/, '-', /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
  });
}
import maskInput from 'c/textMask';

async renderedCallback() {
  const input = this.template.querySelector('lightning-input');
  maskInput({
    inputElement: input,
    mask: [/\d/, /\d/, /\d/, '-', /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
  });
}

I've tried multiple libraries (text mask, Inputmask), different values for the loadScript arguments, different querySelector arguments, and a plain input element as opposed to a lightning-input. The best result I've had so far is getting placeholder characters displaying in the input field on focus, ___-__-____, but even in this case, the typing is hindered as the cursor position constantly jumps to the end of the input after each character is typed. The input is not practically usable.

I wonder if the fact that querySelector returns a Proxy object as opposed to the actual DOM element is causing the issue.

  • Why not provide 3 input texts of shorter width of type='password' and hypen in between them? – Pranay Jaiswal Jul 23 '19 at 20:22
  • Chris, did you ever figure this out? – Jeremy A. West Oct 24 '19 at 16:10
  • @JeremyA.West Unfortunately I concluded that, since Salesforce gives you a Proxy object back instead of the raw DOM element, it is currently not possible to do any sort of on-the-fly masking of an input value. I settled for a LWC that grabs the value after it has been typed, formats it appropriately, puts it back in the field, and runs validation. When the user focuses on the input field it removes the mask and lets them edit the "raw" value again. – Chris Nov 13 '19 at 18:02
2

Unfortunately I concluded that, since Salesforce gives you a Proxy object back instead of the raw DOM element, it is currently not possible to do any sort of on-the-fly masking of an input value. I settled for a LWC that grabs the value after it has been typed, formats it appropriately, puts it back in the field, and runs validation. When the user focuses on the input field it removes the mask and lets them edit the "raw" value again:

HTML

<template>
    <lightning-input
        type="text"
        pattern="[0-9]{3}-[0-9]{2}-[0-9]{4}"
        onfocus={strip}
        onblur={mask}
        onchange={handleChange}
        value={value}
    ></lightning-input>
</template>

JavaScript

const applyMask = input => {
    let value = input.replace(/-/g, '');
    if (value.length >= 6) {
        value = `${value.slice(0, 3)}-${value.slice(3, 5)}-${value.slice(5)}`;
    } else if (value.length >= 4) {
        value = `${value.slice(0, 3)}-${value.slice(3)}`;
    }
    return value;
};

const removeMask = input => input.replace(/-/g, '');

export default class SsnInput extends LightningElement {

    /**
     * ...
     */
    @api value;

    connectedCallback() {
        if (this.value) {
            this.value = applyMask(this.value);
        }
    }

    strip(event) {
      event.target.value = removeMask(event.target.value);
    }

    mask(event) {
        event.target.value = applyMask(event.target.value);
        event.target.reportValidity();
    }

    handleChange(event) {
        ...
    }
}
| improve this answer | |
1

Solution is documented here : https://www.mhamzas.com/blog/2020/05/21/adding-an-input-mask-to-a-lightning-web-component/

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.