6

I have the following setup. My mask will show up, but when I type in it it just skips to the end of the line I am not quite sure what I am doing wrong here. I have tried putting all the props in the parent component and passing them all with a spread, That didn't work. I can provide more debugging if someone can give me an idea on where to debugg first and I'll do it.

Thanks ahead of time

import React from "react"
import { useForm } from "react-hook-form"
import MaskedInput from "react-input-mask"

const Quote = () => {
  const { register, handleSubmit, watch, errors } = useForm();
  const [tel, setTel] = React.useState("");

  render(
    <MaskedInput
      mask="(780) 000-0000"
      alwaysShowMask
      onChange={(e) => setTel(e.target.value)}
      value={tel}
      name={data.title}
    >
      {(inputProps) => (
        <input
          ref={register({
            required: true,
            pattern: /^[\+]?[(]?[0-9]{3}[)]?[-\s\.]?[0-9]{3}[-\s\.]?[0-9]{4,6}$/im,
          })}
          value={inputProps.tel}
          name={inputProps.name}
          {...inputProps}
        />
      )}
    </MaskedInput>
  );
};
Anders Kitson
  • 1,413
  • 6
  • 38
  • 98

6 Answers6

4

This solution work for me. You will need the following packages on your package.json:

"react-hook-form": "^7.34.0",
"@hookform/resolvers": "^2.9.7",
"react-input-mask": "^3.0.0-alpha.2",
"@types/react-input-mask": "^3.0.1",

You can install this version of react-input-mask with the comand ...

yarn add react-input-mask@next
yarn add @types/react-input-mask

Here is the code:

<InputMask
  // mask options
  mask={"99.999.999/9999-99"}
  alwaysShowMask={false}
  maskPlaceholder=''
  // input options
  type={'text'}
  placeholder="Ex: 00.000.000/0000-00"
  // react hook form register
  {...register("cnpj", { required: true })}
/>
3

To help others

If you're using not controlled Input Fields (like native input), ou can use a function to mask the input

This cant be used with controlled input fields like (Material UI)

Example @component/input.tsx

import React from 'react'
import { Container, ErrorMessage } from './styles'

interface InputProps {
  label?: string | true
  defaultValue?: string
  name?: string
  type?: string
  mask?: (value: string) => string
  placeholder?: string
  disabled?: boolean
  error?: any
  value?: string
  register?: any
}
const Input: React.FC<InputProps> = ({
  label,
  defaultValue,
  name,
  type,
  mask = (value: string) => value,
  value,
  placeholder,
  disabled,
  error,
  register,
  ...inputProps
}) => {
  return (
    <Container>
      {label && (
        <label htmlFor={name}>
          {(typeof label === 'string' && label) ||
            placeholder ||
            'Preencha este campo'}
        </label>
      )}
      <input
        onChange={e => (e.target.value = `${mask(e.target.value)}`)}
        disabled={disabled}
        ref={register}
        id={name}
        name={name}
        type={type}
        value={value}
        placeholder={placeholder}
        defaultValue={defaultValue}
        {...inputProps}
      />
      {error && <ErrorMessage>{error.message}</ErrorMessage>}
    </Container>
  )
}

export default Input

Usage example @page/form.tsx

function CPFMask(v: string): string {
  v = v.replace(/\D/g, '')
  v = v.replace(/^(\d{3})(\d)/g, '$1.$2')
  v = v.replace(/^(\d{3})\.(\d{3})(\d)/, '$1.$2.$3')
  v = v.replace(/^(\d{3})\.(\d{3})\.(\d{3})(\d)/, '$1.$2.$3-$4')
  v = v.replace(/^(\d{3})\.(\d{3})\.(\d{3})\/(\d{2})(\d)/, '$1.$2.$3-$4')
  return v.substring(0, 14)
}

...

<Input
      type="text"
      mask={CPFMask}
      placeholder="CPF"
      name="cpf"
      label
      register={register({
        required: {
          value: true,
          message: 'CPF é obrigatório',
        },
        pattern: {
          value: /([0-9]{2}[\.]?[0-9]{3}[\.]?[0-9]{3}[\/]?[0-9]{4}[-]?[0-9]{2})|([0-9]{3}[\.]?[0-9]{3}[\.]?[0-9]{3}[-]?[0-9]{2})/i,
          message: 'CPF inválido',
        },
      })}
      error={errors.cpf}
    />
...
Emanuel
  • 2,603
  • 22
  • 24
  • What about with Material UI? There is a CodeBin with it. https://stackoverflow.com/questions/66601928/matrial-ui-with-react-hook-form-and-react-input-mask-not-working – Dory Zidon Mar 12 '21 at 21:39
3

For those who are using react-hook-form version 7, here is an example how to get it to work:

    <Controller
      name="your input name"
      control={control}
      defaultValue=""
      rules={{
        required: true,
      }}
      render={({ field }) => (
        <MaskedInput
          mask="99/99"
          maskChar=""
          value={field.value}
          onChange={field.onChange}
        >
          {(inputProps: any) => (
            <input
              {...inputProps}
              type="text"
            />
          )}
        </MaskedInput>
      )}
    />
kairon
  • 31
  • 1
  • 1
2

Mask format was wrong needed to be in something like this

mask="(+7 (999) 999-99-99)"

Anders Kitson
  • 1,413
  • 6
  • 38
  • 98
1

Here's an example, wrap the children with a function, let's think of InputMask as Controller and children as render. So I put the ref prop on the children to redirect the ref errors directly to the children or render, not the Controller.

<InputMask name="npwp" mask="99.999.999.9-999.999">
  {(inputProps) => (
    <input
      {...inputProps}
      ref={register}
      type="text"
      placeholder="Input NPWP"
    />
  )}
</InputMask>
bl4ckck
  • 169
  • 2
  • 8
0

This is how I did it without using register, and with a different masking library (s-yadav/react-number-format).

A work-around, as I could not get it to work with {...register()}.

<NumberFormat
    type="tel"
    defaultValue={formDefaultValue}
    onValueChange={(values) => {
        // Mirror the value for form validation
        setFormValue("amount", values.value);
    }}
    customInput={(props) => {
        return (
            <Input
                name="amount"
                formatProps={props}
                errors={formErrors}
            />
        );
    }}
/>

Inside Input component:

<input
    {...(formatProps ? formatProps : {})}
/>
Emre
  • 831
  • 11
  • 13