Reputation: 1559
I've got an input field in the body of my document, and I need to format it as the user types. It should have parenthesis around the area code and a dash between the three and four digits after that.
Ex: (123) 456 - 7890
As the user types it should look something like:
(12
(123)
(123) 456
(123) 456 - 78
(123) 456 - 7890
Upvotes: 35
Views: 98470
Reputation: 1559
<input type="tel" id="phone" placeholder="(123) 456 - 7890" maxlength="16" />
window.addEventListener('load', () => {
const phoneInput = document.querySelector('#phone');
phoneInput.addEventListener('keydown', disallowNonNumericInput);
phoneInput.addEventListener('keyup', formatToPhone);
});
const disallowNonNumericInput = (evt) => {
if (evt.ctrlKey) { return; }
if (evt.key.length > 1) { return; }
if (/[0-9.]/.test(evt.key)) { return; }
evt.preventDefault();
}
const formatToPhone = (evt) => {
const digits = evt.target.value.replace(/\D/g,'').substring(0,10);
const areaCode = digits.substring(0,3);
const prefix = digits.substring(3,6);
const suffix = digits.substring(6,10);
if(digits.length > 6) {evt.target.value = `(${areaCode}) ${prefix} - ${suffix}`;}
else if(digits.length > 3) {evt.target.value = `(${areaCode}) ${prefix}`;}
else if(digits.length > 0) {evt.target.value = `(${areaCode}`;}
};
If your HTML looks like:
<input type="text" id="phoneNumber"/>
Your JavaScript function can simply be:
// A function to format text to look like a phone number
function phoneFormat(input){
// Strip all characters from the input except digits
input = input.replace(/\D/g,'');
// Trim the remaining input to ten characters, to preserve phone number format
input = input.substring(0,10);
// Based upon the length of the string, we add formatting as necessary
var size = input.length;
if(size == 0){
input = input;
}else if(size < 4){
input = '('+input;
}else if(size < 7){
input = '('+input.substring(0,3)+') '+input.substring(3,6);
}else{
input = '('+input.substring(0,3)+') '+input.substring(3,6)+' - '+input.substring(6,10);
}
return input;
}
Of course, you'll need an event listener:
document.getElementById('phoneNumber').addEventListener('keyup',function(evt){
var phoneNumber = document.getElementById('phoneNumber');
var charCode = (evt.which) ? evt.which : evt.keyCode;
phoneNumber.value = phoneFormat(phoneNumber.value);
});
And unless you're okay storing phone numbers as formatted strings (I don't recommend this), you'll want to purge the non-numeric characters before submitting the value with something like:
document.getElementById('phoneNumber').value.replace(/\D/g,'');
If you'd like to see this in action with bonus input filtering, check out this fiddle:
http://jsfiddle.net/rm9vg16m/
// Format the phone number as the user types it
document.getElementById('phoneNumber').addEventListener('keyup', function(evt) {
var phoneNumber = document.getElementById('phoneNumber');
var charCode = (evt.which) ? evt.which : evt.keyCode;
phoneNumber.value = phoneFormat(phoneNumber.value);
});
// We need to manually format the phone number on page load
document.getElementById('phoneNumber').value = phoneFormat(document.getElementById('phoneNumber').value);
// A function to determine if the pressed key is an integer
function numberPressed(evt) {
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57) && (charCode < 36 || charCode > 40)) {
return false;
}
return true;
}
// A function to format text to look like a phone number
function phoneFormat(input) {
// Strip all characters from the input except digits
input = input.replace(/\D/g, '');
// Trim the remaining input to ten characters, to preserve phone number format
input = input.substring(0, 10);
// Based upon the length of the string, we add formatting as necessary
var size = input.length;
if (size == 0) {
input = input;
} else if (size < 4) {
input = '(' + input;
} else if (size < 7) {
input = '(' + input.substring(0, 3) + ') ' + input.substring(3, 6);
} else {
input = '(' + input.substring(0, 3) + ') ' + input.substring(3, 6) + ' - ' + input.substring(6, 10);
}
return input;
}
Enter a phone number here: <input type="text" id="phoneNumber" onkeypress="return numberPressed(event);" />
Upvotes: 89
Reputation: 61
This works great for 10-digit US numbers and covers issues like backspacing, removing letters, and changing numbers after typing.
const formatPhone = (phoneNumberString, remove = false) => {
let newPhoneNumberString = ("" + phoneNumberString).replace(/[a-zA-Z]/g, "")
let cleaned = ("" + newPhoneNumberString).replace(/\D/g, "").slice(0, 10)
if (remove) {
return cleaned
}
if (formatPhone(newPhoneNumberString, true).length == 10) {
let match = cleaned.match(/^(\d{3})(\d{3})(\d{4})$/)
if (match) {
return "(" + match[1] + ") " + match[2] + "-" + match[3]
}
}
return newPhoneNumberString
}
To show formatted (555) 555-5555:
console.log(phoneFormat(phoneValue))
To show raw 555555555 (numbers only; good for storage):
console.log(phoneFormat(phoneValue, true))
Upvotes: 0
Reputation: 31
This solution:
- Formats the phone number input like the iPhone phone app does (at least in the US)
- Allows the user to backspace
- Resets the cursor position to where it was before executing the function
It was made with the help of some of the answers above, hope it helps someone 🙂
let previousPhone = ''
function phoneFormat(field) {
const specialCharCount = (field.value.match(/\D/g) || []).length;
let cursorPosition = field.selectionStart;
let input = field.value.replace(/\D/g,'');
const size = input.length;
if (input.substring(0,1) == 1) {
if (size===0) {input=``}
else if (size<2) {input=`+${input} `}
else if (size<4) {input=`+${input.substring(0,1)} (${input.substring(1)}`}
else if (size<8) {input=`+${input.substring(0,1)} (${input.substring(1,4)}) ${input.substring(4)}`}
else if (size<12) {input=`+${input.substring(0,1)} (${input.substring(1,4)}) ${input.substring(4,7)}-${input.substring(7,11)}`}
}else{
if (size>7 && size<11) {input=`(${input.substring(0,3)}) ${input.substring(3,6)}-${input.substring(6)}`}
else if (size>3 && size<8) {input=`${input.substring(0,3)}-${input.substring(3)}`}
}
if (input !== previousPhone) {
previousPhone = input
const specialCharDiff = (input.match(/\D/g) || []).length - specialCharCount;
cursorPosition += specialCharDiff
field.value = input
field.selectionStart = cursorPosition;
field.selectionEnd = cursorPosition;
}
}
<input type="tel" oninput="phoneFormat(this)">
Upvotes: 3
Reputation: 41
Use this function for any type of formation mask
function numericStringMask(str, mask) {
if (!mask) return str;
const numeric = str.replaceAll(/[^\d]/g, '');
let idx = 0;
const formated = mask.split('').map(el => {
if (el === '#') {
el = numeric[idx];
idx++;
}
return el;
});
return formated.join('');
}
Example 1: (123) 456 - 7890
numericStringMask('1234567890', '(###) ### - ####')
Example 2: (123) 456-7890
numericStringMask('1234567890', '(###) ###-####')
Example 3: (11) 90056-7890
numericStringMask('11900567890', '(##) #####-####')
Upvotes: 4
Reputation: 11
For those of you looking for something similar but in the format of ###-###-#### or #-###-###-#### (just dashes, no parentheses) I implemented the below. Pass in the full input field as a parameter.
This function also has the following additional benefits:
dynamically handles 10 digit OR 11 digit numbers with leading country codes (e.g. 11 digit numbers in the format <COUNTRY_CODE>-###-###-####).
automatically resets the cursor position back to where the user expects it to be (e.g. if you made a typo and needed to delete/insert a new digit in the middle of the number, the function will input the number, update the format, and then put the cursor back to where the new digit was inserted (instead of moving the cursor to the end of the input like most solutions do).
const formatPhoneNum = (inputField) => {
const nums = inputField.value.split('-').join("");
const countryCode = '1';
const digits = nums[0] === countryCode ? 1 : 0;
// get character position of the cursor:
let cursorPosition = inputField.selectionStart;
// add dashes (format 1-xxx-xxx-xxxx or xxx-xxx-xxxx):
if (nums.length > digits+10) {
inputField.value = `${digits === 1 ? nums.slice(0, digits) + '-' : ""}` + nums.slice(digits,digits+3) + '-' + nums.slice(digits+3,digits+6) + '-' + nums.slice(digits+6,digits+10);
}
else if (nums.length > digits+6) {
inputField.value = `${digits === 1 ? nums.slice(0, digits) + '-' : ""}` + nums.slice(digits,digits+3) + '-' + nums.slice(digits+3,digits+6) + '-' + nums.slice(digits+6,nums.length);
}
else if (nums.length > digits+5) {
inputField.value = `${digits === 1 ? nums.slice(0, digits) + '-' : ""}` + nums.slice(digits,digits+3) + '-' + nums.slice(digits+3,nums.length);
}
else if (nums.length > digits+3) {
inputField.value = `${digits === 1 ? nums.slice(0, digits) + '-' : ""}` + nums.slice(digits, digits+3) + '-' + nums.slice(digits+3, nums.length);
}
else if (nums.length > 1 && digits === 1) {
inputField.value = nums.slice(0,digits) + '-' + nums.slice(digits, nums.length);
}
// reseting the input value automatically puts the cursor at the end, which is annoying,
// so reset the cursor back to where it was before, taking into account any dashes that we added...
// if the character 1 space behind the cursor is a dash, then move the cursor up one character:
if (inputField.value.slice(cursorPosition-1, cursorPosition) === '-') {
cursorPosition++;
}
inputField.selectionStart = cursorPosition;
inputField.selectionEnd = cursorPosition;
}
<input type="tel" pattern='^(1-)?[0-9]{3}-[0-9]{3}-[0-9]{4}' oninput='formatPhoneNum(this)' placeholder="Phone Number">
Upvotes: 0
Reputation: 11
While it's true that @legendary_Linus answer works link to that here https://stackoverflow.com/a/30058928/16559479
This is so much simpler
HTML
<input id="phoneNumber" placeholder="Phone Number" maxlength="16"/>
JAVASCRIPT
const formatToPhone = (event) => {
event.target.value=event.target.value.replace(/\D/g,'');//this enforces that input is numeric
const input = event.target.value.substring(0,10); // First ten digits of input only
const areaCode = input.substring(0,3);
const middle = input.substring(3,6);
const last = input.substring(6,10);
if(input.length > 6){event.target.value = `(${areaCode}) ${middle} - ${last}`;}
else if(input.`enter code here`length > 3){event.target.value = `(${areaCode}) ${middle}`;}
else if(input.length > 0){event.target.value = `(${areaCode}`;}
};
const inputElement = document.getElementById('phoneNumber');
inputElement.addEventListener('change',formatToPhone);
here is the code in action https://jsfiddle.net/1xiscool/5146s7pv/2/
Upvotes: 1
Reputation: 151
I studied the various solutions here and came up with this, which I believe is short, sweet, and simple. It still leaves the cursor at the end if you remove an interior digit, but otherwise works perfectly. This is the kind of solution I came here looking for, and what I think the OP wanted.
HTML
<input id="phone" onInput="this.value = phoneFormat(this.value)"/>
Javascript
function phoneFormat(input) {//returns (###) ###-####
input = input.replace(/\D/g,'').substring(0,10); //Strip everything but 1st 10 digits
var size = input.length;
if (size>0) {input="("+input}
if (size>3) {input=input.slice(0,4)+") "+input.slice(4)}
if (size>6) {input=input.slice(0,9)+"-" +input.slice(9)}
return input;
}
Update I found a way to make it even a tiny bit neater:
Javascript
function phoneFormat(input) {//returns (###) ###-####
input = input.replace(/\D/g,'');
var size = input.length;
if (size>0) {input="("+input}
if (size>3) {input=input.slice(0,4)+") "+input.slice(4,11)}
if (size>6) {input=input.slice(0,9)+"-" +input.slice(9)}
return input;
}
Upvotes: 14
Reputation: 56
let telEl = document.querySelector('#phoneNum')
telEl.addEventListener('keyup', (e) => {
let val = e.target.value;
e.target.value = val
.replace(/\D/g, '')
.replace(/(\d{1,4})(\d{1,3})?(\d{1,3})?/g, function(txt, f, s, t) {
if (t) {
return `(${f}) ${s}-${t}`
} else if (s) {
return `(${f}) ${s}`
} else if (f) {
return `(${f})`
}
});
})
Phone Number: <input type="text" id="phoneNum" maxlength="14" />
Upvotes: 0
Reputation: 19
I recently stumbled across the same problem, here is the solution I used. It is quite simple and also checks the form before the user submits the form.
function myFunction() {
var inpField = document.getElementById("myInput");
var l = inpField.value.length;
var key = event.inputType;
var toDelete = (key == 'deleteContentBackward' || key == 'deleteContentForward') ? 'delete' : 'keep';
//deleteContentBackward and deleteContentForward are obtained when user hits backspace or delete keys. To get extra info from inputType, check: InputEvent https://www.w3schools.com/jsref/obj_inputevent.asp
if (toDelete === 'delete') {
alert('Please, enter your number again.');
// clears the whole input field
inpField.value = "";
}
// then, checks the inputs to add the required pattern. Also helps the user to check if number is typed correctly
switch (l) {
case 1:
inpField.value = "(" + inpField.value;
break
case 4:
inpField.value = inpField.value + ") ";
break
case 9:
inpField.value = inpField.value + " - ";
break
case 17:
// prevents user from typing more numbers than necessary:
inpField.value = inpField.value.slice(0, l - 1)
}
}
<form>
<input type="tel" id="myInput" oninput="myFunction()" placeholder="(###) ### - ####" required pattern="\([0-9]{3}\) [0-9]{3} - [0-9]{4}">
<!-- oninput is trigued when the input changes, check https://www.w3schools.com/jsref/event_oninput.asp -->
<!-- Used regex to check the input value before submit from user -->
<input type="submit">
</form>
(123) 456 - 7890
Upvotes: 1
Reputation: 246
Here is a simple solution in React.
(getFormattedPhone
and getDigitOnlyPhone
are from the answer that @Legendary_Linux gave)
We pass a formatted value
to our input so that it correctly displays like this: (123) 456 - 7890
In the onChange
, we use getDigitOnlyPhone
to pass up a string of digits, rather than our formatted phone number.
import React from 'react'
const getDigitOnlyPhone = value =>
value.toString().replace(/\D/g, '').substring(0, 10)
const getFormattedPhone = value => {
if (!value) return ''
const phone = getDigitOnlyPhone(value)
const areaCode = phone.substring(0, 3)
const middle = phone.substring(3, 6)
const last = phone.substring(6, 10)
let formattedPhone = ''
if (phone.length > 6) {
formattedPhone = `(${areaCode}) ${middle} - ${last}`
} else if (phone.length > 3) {
formattedPhone = `(${areaCode}) ${middle}`
} else if (phone.length > 0) {
formattedPhone = `(${areaCode}`
}
return formattedPhone
}
export const PhoneInput = ({ value, onChange, ...props }) => (
<input
{...props}
maxLength={16}
pattern="[0-9]{3}-[0-9]{3}-[0-9]{4}"
value={getFormattedPhone(value)}
onChange={e => {
const phone = getDigitOnlyPhone(e.target.value)
if (value || phone) onChange(phone)
}}
/>
)
Upvotes: 0
Reputation: 47
I don't have enough points to add a comment to @Rey's answer above, but you don't need to do all that in order to take the backspace or delete key into account. All you have to do is if the delete or backspace key was pressed, return the string as it is already because the formatting will already be there.
The OP asked for a pure javascript solution, so I have included a function to capture the event keyCode. You could do that in jQuery if you are following @Rey's answer.
document.getElementById('phoneNumber').addEventListener('keyup', function(evt) {
var charCode = (evt.which) ? evt.which : evt.keyCode;
if(charCode == 8 || charCode == 46) return true;
else this.value = formatPhone(this.value);
}, false);
function formatPhone(str) {
if(str.length == 0) return str;
if(delKey) return str;
var phone = '(';
str = str.replace(/\D/g, '').substring(0,10);
if(str.length < 3) {
phone += str;
} else if(str.length < 6) {
phone += str.substring(0, 3) + ') ';
if(str.length > 3) phone += str.substring(3, str.length);
} else {
phone += str.substring(0, 3) + ') ' + str.substring(3, 6) + '-' + str.substring(6, 10);
}
return phone;
}
Upvotes: 0
Reputation: 2767
let telEl = document.querySelector('#phoneNum')
telEl.addEventListener('keyup', (e) => {
let val = e.target.value;
e.target.value = val
.replace(/\D/g, '')
.replace(/(\d{1,4})(\d{1,3})?(\d{1,3})?/g, function(txt, f, s, t) {
if (t) {
return `(${f}) ${s}-${t}`
} else if (s) {
return `(${f}) ${s}`
} else if (f) {
return `(${f})`
}
});
})
Phone Number: <input type="text" id="phoneNum" maxlength="14" />
Upvotes: 2
Reputation: 237
Earlier answers didn't consider what happens when a user makes a mistake and deletes some of the entered digits.
For those looking for a jQuery solution, this reformats on every keyup event, and removes the additional characters and whitespace when the user is editing the number.
$('#phone').keyup(function(e){
var ph = this.value.replace(/\D/g,'').substring(0,10);
// Backspace and Delete keys
var deleteKey = (e.keyCode == 8 || e.keyCode == 46);
var len = ph.length;
if(len==0){
ph=ph;
}else if(len<3){
ph='('+ph;
}else if(len==3){
ph = '('+ph + (deleteKey ? '' : ') ');
}else if(len<6){
ph='('+ph.substring(0,3)+') '+ph.substring(3,6);
}else if(len==6){
ph='('+ph.substring(0,3)+') '+ph.substring(3,6)+ (deleteKey ? '' : '-');
}else{
ph='('+ph.substring(0,3)+') '+ph.substring(3,6)+'-'+ph.substring(6,10);
}
this.value = ph;
});
Upvotes: 10
Reputation: 87
To add some additional ease for the user, I'd actually update the string to automatically include a ")" or "-" as the user reaches certain characters, to prevent them from adding, say two dashes. (555)555--5555
if(size === 0) {
input = input;
}
else if (size === 3) {
input = '('+input.substring(0,3)+') '
}
else if (size < 4) {
input = '('+input;
}
else if (size === 6) {
input = '('+input.substring(0,3)+') '+input.substring(3,6)+' -';
}
else if (size > 6) {
input = '('+input.substring(0,3)+') '+input.substring(3,6)+' - '+input.substring(6,10);
}
return input
Upvotes: 0
Reputation: 3767
I'm not a fan of the slicing stuff. I'd advise using .replace(), pass it a regex, capture the pieces of the phone number, and then output it the way you need it. If you can read regex, it's a much better programmatic way to approach the issue, and dead simple to alter the format.
var phoneNumber = "1234567899";
var formatted = phoneNumber.replace(/(\d{1,2})(\d{1})?(\d{1,3})?(\d{1,4})?/, function(_, p1, p2, p3, p4){
let output = ""
if (p1) output = `(${p1}`;
if (p2) output += `${p2})`;
if (p3) output += ` ${p3}`
if (p4) output += ` ${p4}`
return output;
});
Note: I haven't added any sort of whitespace, non number stripping but you can add that as well.
Upvotes: 8