use-mask-input icon indicating copy to clipboard operation
use-mask-input copied to clipboard

Backspace key writes "Ba" or "BB" in the Input when used with Mask "99.999.999-[99]|[aa]"

Open matheusfscit opened this issue 1 year ago • 14 comments

Description:

When using the mask "99.999.999-[99]|[aa]" with the use-mask-input library, pressing the Backspace key results in the word "Backspace" being written into the input. However, since the mask allows only 2 characters for letters, it ends up writing "Ba" or "BB".

Code Example:

<Input
  type="text"
  label={
    <span>
      RG: <span className="text-red-500">*</span>
    </span>
  }
  variant="bordered"
  defaultValue={control._formValues["rg"]}
  isInvalid={!!errors.rg}
  labelPlacement="outside"
  placeholder="xx.xxx.xxx-xx"
  errorMessage={errors.rg?.message as string}
  className="max-w-[40rem]"
  {...registerWithMask("rg", "99.999.999-[99]|[aa]", {
    required: true,
    autoUnmask: true,
  })}
/>

image

Steps to Reproduce:

Use the mask "99.999.999-[99]|[aa]" in an input field. Type a valid RG number. (In Brazil some states RG has letters at the end) Press the Backspace key.

Expected Behavior:

The Backspace key should delete the previous character, not write "Ba" or "BB" into the input field.

Actual Behavior:

Pressing the Backspace key writes "Ba" or "BB" into the input field.

Environment:

Library Version: 3.4.0 I'm using the mask with react-hook-form

This issue seems to occur specifically with masks that include optional letter characters. It prevents proper user experience by inserting unwanted characters when attempting to delete.

Thank you for looking into this issue.

matheusfscit avatar Sep 04 '24 03:09 matheusfscit

for some reason when i use the hook. The Backspace and Delete are write instead erase the input

image image

Ilwel avatar Sep 13 '24 18:09 Ilwel

Same problem, here is kind of confusing.

danim47c avatar Sep 20 '24 09:09 danim47c

Same

ghost avatar Oct 04 '24 18:10 ghost

Same thing, any workarounds for this?

huksley avatar Oct 30 '24 14:10 huksley

Horrible hack but it works...

useEffect(() => {
  if (value && value.indexOf("BACKSPACE") > -1) {
    setValue(value.replace("BACKSPACE", "_"));
  }
}, [value]);

<input
  ref={masked ? withMask(mask) :undefined}
  value={value}
  onChange={e => {
    setValue(e.target.value);
  }}
  onFocus={() => {
    setMasked(true);
  }}
  onBlur={() => {
    setMasked(false);
  }}
/>

huksley avatar Oct 30 '24 18:10 huksley

This is a simple workaround that worked for me. You can implement more custom logic if needed in the handleBeforeWrite function

const InputMaskField = ({ field }: { field: Field }) => {
  const {
    register,
    setValue,
    formState: { errors },
  } = useFormContext();
  const registerWithMask = useHookFormMask(register);

  const handleBeforeWrite = (event: KeyboardEvent) => {
    if (event.key === 'Backspace' || event.key === 'Delete') {
      setValue(field.key, '', {
        shouldValidate: true,
        shouldDirty: true,
      });
      return { rewritePosition: 0 };
    }
    return { rewritePosition: undefined };
  };

  return (
    <div className="w-full flex flex-col gap-2">
      <Input
        id={field.key}
        type="text"
        placeholder={field?.placeholder || ''}
        {...registerWithMask(field.key, field.mask || [], {
          autoUnmask: true,
          onBeforeWrite: handleBeforeWrite,
        })}
      />
      {errors[field.key]?.message && (
        <FieldError>{String(errors[field.key]?.message)}</FieldError>
      )}
    </div>
  );
};

kimdat546 avatar Nov 27 '24 05:11 kimdat546

Workarounds are kinda working but have disadvantages. The only reason I could not use the lib is the error shown above... Hope the author will quickly fix that.

PatrickInFrontEnd avatar Jan 22 '25 16:01 PatrickInFrontEnd

Yet another partial workaround is to just define letters you expect to be typed. In my case just letter 'X'.

<Input
  {...field}
  ref={withMask("9999-999(9|X)", {
    definitions: {
      X: {
        validator: "[xX]",
        casing: "upper",
      },
    },
  })}
/>

SIN3d73 avatar Mar 18 '25 22:03 SIN3d73

This is still ocurring as of today

RianReisBRQ avatar Aug 20 '25 17:08 RianReisBRQ

Requires InputMask update https://github.com/RobinHerbots/Inputmask/commit/aba4c29d045daa349891c36bc49c458d3550fdc8

redalpha01 avatar Aug 27 '25 14:08 redalpha01

@RianReisBRQ I installed the next version of inputmask and created myself a similar class to the one in here (I dont use react hook form)

import Inputmask from 'inputmask';
type Options = Inputmask.Options;
type Input = HTMLInputElement | HTMLTextAreaElement | HTMLElement | HTMLInputElement | null;

export function withMask(mask: string, options?: Options): (input: Input) => void;
export function withMask(options: Options): (input: Input) => void;
export function withMask(): (input: Input) => void;

export function withMask(maskOrOptions?: string | Options | null, options?: Options): (input: Input) => void {

    return (input: Input) => {
        if (!(
            typeof window !== 'undefined'
            && window.document
            && window.document.createElement
        )) return;

        let maskInput: Inputmask.Instance;

        if (typeof maskOrOptions === 'string') {
            maskInput = Inputmask(maskOrOptions, options);
        } else if (maskOrOptions && typeof maskOrOptions === 'object') {
            maskInput = Inputmask(maskOrOptions);
        } else if (options) {
            maskInput = Inputmask(options);
        } else {
            // Default empty mask if no parameters
            maskInput = Inputmask();
        }

        if (input) {
            maskInput.mask(input);
        }
    }
}

Only issue is that using regex still has the backspace issue so I replaced it with a mix of mask and definitions (like the suggestion from march).

redalpha01 avatar Aug 27 '25 18:08 redalpha01

That "BA" annoying bug can be even easily replicated in the very first manual example:

ref={withMask("AA99 AAA", {
    placeholder: "_",
    showMaskOnHover: false,
})}

You simply add that to an input, type anything, then backspace it and voila - a cursed "BA" appears

vitpankin avatar Oct 23 '25 10:10 vitpankin