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)