How to create input masks in HTML
If you have questions or comments or bugs report, or a change to make, be sure to use the project’s new homepage: Flexible JS Formatting Libraries
Note that this is not compatible with all browsers, has known problems and limitations, and I am not maintaining it or replying to requests for help. Thanks! (But also note that you are free to change and redistribute under the license terms, which you should read after downloading)
Have you ever wanted to apply an input mask to an HTML form field? Input masks are common in traditional GUI applications, but HTML has no such feature. This article introduces a library that adds input masks to form fields with unobtrusive JavaScript.
What’s an input mask?
Input masks are guides to help users enter data in the correct format. They typically do not actually validate data; they just ensure the right types of characters are entered in the right places. Typical uses are for dates, times, social security numbers, phone numbers, and credit card numbers. The user enters un-formatted input, and the mask takes care of adding dashes and other separators in appropriate places.
For example, in the United States most people use MM/DD/YY format to write dates. A well-written GUI application honors the user’s locale and creates an appropriate input mask, such as ##/##/##, for date entry. The user types the numbers, and the program inserts the slashes. If the user types something other than a number, that character is discarded, not entered into the field.
How to do this with JavaScript
There are several problems you need to solve to simulate this in a web browser. First things first: let’s state the requirements.
- Help the user avoid entering invalid characters.
- Automatically insert separators as the user types.
- Constrain the length of the input.
Second, let’s create a spec for the masking syntax. In Windows Forms programming, controls have a Mask property, and other GUI libraries have similar functionality. The full behavior of these masks is complex. For an example, see the MSDN documentation for masked edit controls. You can get a lot of that functionality with a simpler specification, though. The following will suffice for many uses:
- The mask only allows one type of character for the entire mask. For example, the mask can allow either all digits or all alphanumerics, but you can’t constrain one character to be a digit while letting other characters accept alphanumerics.
- The mask specifies the placeholders for input with spaces, and separators as non-spaces.
An example mask, then, has two parts: the format, which says which places can accept user input, and the type, which says what type of character can go in those places. We’ll see how to actually do this later.
The third problem is to unobtrusively attach the masking functionality to input fields, with gracefully degrading behavior if the browser doesn’t support it, and without adding a lot of markup to your forms to specify the mask format and type. This is easy, using the principles I laid out in an earlier article on using classes to specify data types. This technique is 100% appropriate because classes aren’t just hooks for CSS, they’re general-purpose processing information. This lets you easily specify a) which inputs get masks, and b) which type of mask they get.
How it works
To add masks to form fields, reference my library, then make the page’s load event fire the Xaprb.InputMask.setupElementMasks() function in my library. This will find all elements with the class input_mask, which specifies that the element should get a mask. Each element should also have a mask_??? class, where the ??? specifies which mask to attach. The library takes care of the rest.
By the way, this library depends on the Prototype library, so you will also need to reference that in your page. If you don’t, you won’t get an error, but nothing will happen.
The setup function iterates over the elements and connects a callback to the onkeypress event. The callback is created by another function. To decide which mask to apply, it does a regular expression match against the element’s className. If the element’s class is “input_mask mask_date_us“, the regular expression captures “date_us,” and looks up the date_us mask. Here’s how that is defined:
date_us: {
format: ' / / ',
regex: /\d/,
}
The format property is a string with spaces where input should go, and other characters get inserted automatically. The regex property is a regular expression that matches a valid character, in this case a digit.
Here’s how the callback function works: when it fires, it checks each character in the form field’s value. If there’s a space in that place in the mask’s format string, it looks to see if the character matches the mask’s regular expression. If so, the character is valid for that place in the input; if not, the character is rejected. If there isn’t a space in that place in the format string, the character from the format string is copied into the form field (this is how separators are automatically inserted).
Demonstration
Enough talk, let’s see it in action. This demonstration of Javascript form input masks shows a few of the masks I discussed above: US date, time, and phone number.
If you like the way the form input fields look, you can thank the fine folks at Particletree. I borrowed the styling from their article on how to make forms suck less (it makes the borders of the input areas easier to see).
Limitations
Since this is really just a hack on top of existing HTML form inputs, there are some things that will never work quite as well as a natively designed widget (the same is true for my JavaScript Combo Box widget). Here are some of the limitations:
- No unicode or international characters (this might be easy to fix).
- No spaces as placeholders. Sometimes you might want spaces between user input, rather than non-space separators.
- Only one type of character for the entire input; you can’t constrain the first character to be a digit, and the second a letter.
- It doesn’t show the mask ahead of time and let the user ‘fill in’ the missing characters; instead, it reveals the mask as the user types.
- You can’t have two adjacent separators.
- You can’t type into the middle of the text; all input you type is appended to the end.
- It hijacks things like Ctrl+A to select all.
Despite the length of that list, these are such minor things (except for maybe international characters) that it’s practically a complete implementation. And as far as I know, everything here could be solved easily. I just haven’t done it, because you haven’t yet told me which things are problems for you (hint, hint: leave a comment, and patches are very welcome). I deliberately kept things really simple in this first version. Future versions can get fancier, or not.
Conclusion
So that’s it! Simple, lightweight, intuitive input masks. With a proper form validation library on the back-end, you should be able to use this to help your users enter data in the format you desire. Again, let me know what you think, and by all means improve this, and send me the results!



Awesome. Thanks for this!
sn
3 Nov 06 at 3:18 am
This looks pretty groovy as a starting point for HTML input masks. One thing that put me off though was that whilst you might actually type, say, “12/07/2006″ into the date field the forward slash characters would not actually appear until you typed the first numeral of the next section of date.
As a user this was slightly confusing as I would expect that character to appear as I typed it rather than being forcibly ignored and then manually added once I typed the next numeric character.
I’d also absolutely love to be able to see some sort of grayed out instance of the input mask on the input field as I’m entering data into it, but this is a wish rather than a worry.
Definitely very cool as a proof of concept though!
Neil Crosby
3 Nov 06 at 8:46 am
Very cool concept! Nice work.
Nate K
3 Nov 06 at 10:18 am
Neil, I was thinking the same thing about the grayed-out representation, but I don’t know how to do that except with a background image, which might not match the user’s font :-/
I was also thinking of how to let the user type the separator as an indication that they’re ready for the next ‘field’ in the input string. This would involve a default character for any un-filled spaces. So, for example in the date field, I might want to type 5/5/2006. Every time I type / the script would look ahead and see that I just typed the ‘next’ separator character. It would then left or right-pad the current field’s value with the default, add the separator, and I’d be in the next field. To clarify: I type 5, then /. The script left-pads the 5 with 0 and adds /. I type 5/ again, and again the script converts that to 05/. The end result is 05/05/2006.
Another improvement might be to anticipate the next separator, so after (in your example) you type 12, it would add the slash, not waiting for you to type the 0.
Maybe I should make a proof of concept and see if it’s usable, and whether other people like it.
Xaprb
3 Nov 06 at 11:44 am
[...] Xaprb has got a fantastic article about creating input masks using javascript in HTML input fields. Definately a must read. How come I didn’t think of that? [...]
zed23 » Blog Archive » Quick updates
3 Nov 06 at 1:29 pm
Erm I’m confused, I’m not really sure what this is trying to acheive or maybe the example is broken???
e.g. I can enter “:8/90/0654″ for a date and “99:`2′#1″ for a time ? (Note: This was in IE 7).
Gavin Brown
7 Nov 06 at 8:32 am
No, you’re right, it doesn’t cancel input on special characters in IE. I’ve been learning more about this over the last few days, but basically it looks like every browser reports the keyboard event’s keycode differently, in really bizarre ways. For example, IE reports the colon as a non-printable character. I have not yet found a workaround for this. It looks like one of those pain-in-the-butt browser things.
Xaprb
7 Nov 06 at 8:56 am
At first I thought you we’re disabling the inputs. But now I see what you really meant. That is really cool …
Does it work only with numbers or you can use them for anything ?
Sava
Sava
17 Nov 06 at 1:50 pm
It should work with anything you can regex-match, but unfortunately as I mentioned in the above comment, IE is giving me trouble. I haven’t found a workaround yet. I don’t really want to write such specific code. I suppose one thing I could do is write another module to examine an event and return the character in a cross-browser manner, but I haven’t had time to do that yet.
Xaprb
17 Nov 06 at 2:18 pm
In IE7 the numeric keypad doesn’t work to enter numbers. This is because the regexp doens’t match with the keypad characters. To correct this I added the following code to the applyMask function:
// correction for numeric keypad if (key >= 96 && key <=105) { key = key - 48; } var ch = String.fromCharCode(key);John Reeher
8 Dec 06 at 11:31 am
I have been playing with this for a few days on some of my pages. One page has multiple forms in an absolute position. They are swapped using $(id).style.visibility. The init for the input masks won’t work if they are hidden. I was trying to call it when the view was swapped, but if you go to one view then back to the other, it is called twice. If you start to enter data into a field, it will duplicate whatever you type. If you type “a” it will put “aa”, “1″ becomes “11″, etc. Is there a way to kill and reinit on each view call?
kyle
17 Dec 06 at 4:10 am
It sounds like two elements in your HTML document have the same ID. This is invalid and will cause all sorts of problems. IDs are supposed to be globally unique. You should consider running your document through a validator.
Xaprb
18 Dec 06 at 3:43 pm
I had a question about the delete key. With the mask it appears to handle for the backspace key great, but for some reason when I highlight the mask and hit the delete key, it doesn’t erase the date that I had entered into the mask.
Aaron Petersen
4 Jan 07 at 8:58 pm
That’s because the code cancels the event unless the key pressed is a printable character. Not the best way to do it, I know.
I have tried to completely solve this and other problems, but capturing events and trying to figure out what the key pressed was is a thorny problem, with ridiculous browser incompatibilities. I have come to the conclusion that this is not a good way to simulate an input mask. However, I don’t know anything else that would work at the moment. It’s uglier than I thought when I wrote this article.
Xaprb
5 Jan 07 at 11:44 am
Q – I am using this to limit number inputted but it seems to prevent users in IE6+ from inputting using the keypad on the right. ie they can only input numbers fro the top of the keyboard. Is there anyway around that?
ferg
12 Feb 07 at 3:15 pm
Not that I’m aware of.
Xaprb
12 Feb 07 at 3:33 pm
On ie7 prototype library v 1.4 caused an error.
I downloaded v1.5, but mask doesn’t work any more.
Mindaugas
16 Feb 07 at 3:33 pm
emmm sorry, now it again works.. mistery..thank you for this post anyway.
Though i left prototype version 1.5, last one.
Mindaugas
16 Feb 07 at 9:22 pm
[...] I stumbled across this very nice script by Xaprb that creates input mask for form fields. It’s a brilliant idea to auto fill some of the indentations, especially in date and time input fields for the users. I rewrote some of the codes to fix a couple issues: [...]
Daily misery » Blog Archive » Input mask revisit
5 Mar 07 at 3:55 pm
hey,
Is it posible to insert only numeric and a sign like ‘-’
example: 12-542-45-63 or like a price 12,36
How do i have to write that
num: { format: ' - ' , regex: /\d/ // here i would like to include ' - ' sign },leung
4 May 07 at 7:21 am
Good day, everyone…
I changed the input masks’ place holders to enable us to use spaces in our masks…
Here is a sample of the new masks:
date: { format: '§§/§§/§§§§', // Werner Cloete - 02/05/2007 - Make use of a new "§" mask place holder regex: /\d/ }, phone: { format: '§§§ §§§-§§§§', // Werner Cloete - 02/05/2007 - Make use of a new "§" mask place holder regex: /\d/ }The “§” character is created with [Alt]+21…
I also updated the code to display the mask’s next set character as you type…so, for example, if you’re using the date mask, and you have already typed “12″, the “/” will immediately appear…
Here is the updated code:
/* if ( mask.format.charAt(pos - 1) != ' ' ) */ // Werner Cloete - 02/05/2007 - Commented out the code if ( mask.format.charAt(pos) != '§' ) // Werner Cloete - 02/05/2007 - Changed the code to use the new "§" mask place holder { /* str = this.value + mask.format.charAt(pos - 1) + ch; */ // Werner Cloete - 02/05/2007 - Commented out the code str = this.value + ch + mask.format.charAt(pos); // Werner Cloete - 02/05/2007 - Changed the order in which the strings are concatenated }I hope that this will prove useful…
Yours sincerely
Werner
Werner Cloete
8 May 07 at 10:03 am
You have this licensed under the GPL. I’d like to use this code in on of my web application products. Will you give your permission for this use?
Oliver
13 Jun 07 at 7:18 pm
It’s LGPL. I don’t want to license it any more liberally than that, though of course you are free to inspect the source and design your own implementation of the same thing.
Xaprb
13 Jun 07 at 9:13 pm
thank u so much for this, it really helped me a lot. can the delete key and the numbers on the num pad be activated? if yes, please let me know. thanx once again.
Jay Nair
2 Aug 07 at 8:55 am
it does not work in IE7. “/.;’,” all there symbol can be inserted
Jimmy6
7 Jan 08 at 12:33 pm
Very nice, helpful!
Is there a smaller version of prototype.js available, with only the necessary code for this mask?
Rhett135
4 Mar 08 at 10:41 am
Can I place a mask inside the text field pre populated. This will give a clue to the end user entering the date. Thanks. I am unable to do so till now.
Muhammad Asif
1 Apr 08 at 5:24 am
Hi all,
I’m sorry but I don’t have time or need to maintain this or help people with it. I would love it if someone would take on the task of maintaining it. Please leave a comment with the URL of the new home for it, if you decide to maintain and improve it.
Xaprb
1 Apr 08 at 10:11 am
To enable the keypad in IE7.0 replace the applyMask function with the code below.
applyMask: function(event) {
var match = /mask_(\w )/.exec(this.className);
if ( match.length == 2 && Xaprb.InputMask.masks[match[1]] ) {
var mask = Xaprb.InputMask.masks[match[1]];
var key = Xaprb.InputMask.getKey(event);
// correction for numeric keypad
if (key >= 96 && key
Mike
12 Jun 08 at 11:07 am
Thank’s a lot for this usefull script.
I notice that setupElementMasks should use : $$(‘.input_mask’)
instead of document.getElementsByClassName
(I don’t know why, but getElementsByClassName give me an error with prototype 1.6.0.2)
bisi2poche
22 Aug 08 at 5:27 am
getElementsByClassName is a native function in Firefox 3 and is thus being deprecated is Prototype.
Another feature I added is pre-filling characters so that you know it’s happening. Otherwise you may wonder why it’s not letting you type a hyphen your SSN.
if ( mask.format.charAt(pos – 1) != ‘ ‘ ) {
str = this.value + mask.format.charAt(pos – 1) + ch;
}
// Added by titi@medtouch.com 2009-03-05 so that it fills in
// chars ahead of the cursor as well
if ( mask.format.charAt(pos) != ‘ ‘ ) {
str += mask.format.charAt(pos);
}
I think this might have an issue if it has to back-fill and forward-fill on the same char, but that can be fixed should anyone ever have a pattern that required it.
Titi Alailima
5 Mar 09 at 1:44 pm
Titi,
Please request developer access to http://code.google.com/p/flexible-js-formatting/ and I’ll grant you commit rights.
Xaprb
8 Mar 09 at 10:02 am
I have uploaded my changes to the SVN repository at Google, so if anyone wants it they can get it. Email me at tigretigre@gmail.com if you want any more additions/fixes as Baron is not up for maintaining this himself any more.
Titi Alailima
9 Mar 09 at 12:58 pm
[...] How to create input masks in HTML – HTML Input Mask, por Baron Schwartz (Xaprb). Novo repositório do código em Google Code: Flexible JS Formatting Libraries. [...]
Blog do Márcio d’Ávila » Máscara de formatação em campos de formulário HTML
19 Mar 10 at 7:49 am
Thank you very much ! Good job !
Oana
11 Mar 13 at 4:38 am