Article cover image

Formatting a Phone Number Input

  • Drayke
    Drayke
    Frontend Developer

The input element

Create an input of type="tel" and add the class phone-number-input to it.

<input type="tel" class="phone-number-input" />

Listening for input change

Next, we’ll get our input element and attach the "input" event listener which will fire when the value of our input has changed.

const phoneNumberInput = document.querySelector('.phone-number-input')
phoneNumberInput.addEventListener('input', handleInput)

We can go ahead and create our handleInput function that will be executed when the input event is fired.

Add the InputEvent type to our event parameter, and we will make a type assertion to let TypeScript know that our target is an InputElement. Then, we’ll re-assign target.value to the return value of formatPhoneNumber.

const handleInput = (e: InputEvent) => {
    const target = e.target as HTMLInputElement    
    target.value = formatPhoneNumber(target.value) 
}

Formatting function

Lastly, let’s create the formatPhoneNumber function and actually format the value.

const formatPhoneNumber = (value: string) => { 
    value = value.replace(/\D/g, '')

    if (value.length > 3) {
        const areaCode = value.slice(0, 3)
        const beforeHyphen = value.slice(3, 6)
        const afterHyphen = value.slice(6, 10)    
        value = `(${areaCode}) ${beforeHyphen}${
            afterHyphen ? `-${afterHyphen}` : ''
            }`
        }

    return value
}

Right off the hop we filter out any unwanted values by replacing all non-digits characters.

value = value.replace(/\D/g, '')

This will prevent the user from entering any letters or special characters manually.

In our if statement we check if the input value if greater than 3, and if it is, we use the string slice method. This extracts part of the value and returns a new string without modifying the original value. The slice method takes two parameters:

indexStart - the index of the first character you want to return in the returned string

indexEnd - the index of the first character you want to exclude from the returned string.

We break down the input value into three parts, areaCode, beforeHyphen, and afterHyphen which we’ll use to achieve this format (###) ###-####.

Using the slice method in this way will also limit the number of characters the user can type by having our last included value index be 9 because indexEnd is 10 for afterHyphen.

For the final step, we can add everything together with template literals, which will allow us to concatenate our strings and include logic to conditionally alter the return value. We use a ternary operator that will return our afterHyphen value with a hyphen at the front of the string only if afterHyphen has a value, else we will return an empty string.

The whole thing all together.

const formatPhoneNumber = (value: string) => {   
    value = value.replace(/\D/g, '')

    if (value.length > 3) {     
        const areaCode = value.slice(0, 3) 
        const beforeHyphen = value.slice(3, 6)
        const afterHyphen = value.slice(6, 10)

        value = `(${areaCode}) ${beforeHyphen}${   
            afterHyphen ? `-${afterHyphen}` : ''     
        }`
   }    

   return value 
}

const handleChange = (e: InputEvent) => {   
    const target = e.target as HTMLInputElement
    target.value = formatPhoneNumber(target.value) 
}

const phoneNumberInput = document.querySelector('.phone-number-input')
phoneNumberInput.addEventListener('input', handleChange)