33

I can't get the pattern attribute on a text input to be limited to numbers. According to the javascript regular expressions list, [d] or [0-9] should do it. But in

<input dir="ltr" type="text" title="Enter numbers only." pattern="[\d]{9}" id="uid" name="1" placeholder="Enter UID" required="'required'" class="required placeholder" minlength="9" maxlength="9" autocomplete="off" />

it doesn't work for me (in any browsers). I have to add js validation such as the following (decided to go this route for simplicity based on this post):

HTML:

onkeypress='return isNumberKey(event)' 

js:

function isNumberKey(evt){
    var charCode = (evt.which) ? evt.which : event.keyCode
    if (charCode > 31 && (charCode < 48 || charCode > 57))
        return false;
    return true;
}

I mainly want to know if there's a way I can get the pattern attribute to work. But also feel free to comment on whether I'm using best practices route for this. I don't want to use HTML5 <input type="number"/> as it's not widely supported enough yet.

Community
  • 1
  • 1
levininja
  • 3,118
  • 5
  • 26
  • 41
  • Have you tried using `[0-9]{9}` instead ? – Ibrahim Najjar Sep 28 '13 at 12:01
  • what browser and version are you using? the pattern attribute is also html and supported only in the latest browsers (i.e. IE9 doesn't support it). – Nicolas Straub Sep 28 '13 at 12:07
  • Seems to be working fine. I added a CSS check to give red when invalid and green when valid: [jsfiddle](http://jsfiddle.net/bHWcu/). – Jerry Sep 28 '13 at 12:11
  • 1
    The validation for the `pattern` attribute will not prevent adding incorrect information, but it will prevent submitting the form. You can also use the CSS selectors @Jerry used in his demo. – Ingo Bürk Sep 28 '13 at 12:13
  • 1
    See this update of @Jerry's fiddle: http://jsfiddle.net/bHWcu/1/ – Ingo Bürk Sep 28 '13 at 12:14
  • @Ingo Nice fiddle you got there :) – Jerry Sep 28 '13 at 12:15
  • I didn't see the `minlength="9"` and `maxlength="9"` on the tag. If exactly nine digits is what you want, my answer wasn't relevant. – T.J. Crowder Sep 28 '13 at 12:16
  • @Sniffer, Yes, I have tried `[0-9]{9}` but also with no effect. @Nicolás Straub Valdivieso Doesn't work for me in latest Chrome, in latest FF, or IE10 or IE9. – levininja Sep 28 '13 at 12:21
  • “Does not work” is not a problem description. Please specify what you expected and what happened instead. Note that the `pattern` attribute is not meant to *prevent* entering data that does not correspond to the pattern, just to signal it as invalid. – Jukka K. Korpela Sep 28 '13 at 12:23
  • @Jukka K. Korpela sorry for not being more descriptive on that point; and yes, I was expecting it to prevent entering data. See accepted answer below. – levininja Sep 28 '13 at 12:31

3 Answers3

65

The validation for the pattern attribute will not prevent writing incorrect information into the field, but it will prevent submitting the form. The element also has an oninvalid event that will be called when the validation fails during the submit.

Alternatively, you can also use the CSS selectors :valid and :invalid to provide instant visual feedback.

Fiddle showing both (based on Jerry's fiddle from the comments): http://jsfiddle.net/bHWcu/1/

<form onsubmit="alert('Submitted');">
    <input dir="ltr" type="text" title="Enter numbers only." pattern="[\d]{9}" id="uid" name="1" placeholder="Enter UID" required="'required'" class="required placeholder" maxlength="9" autocomplete="off" />
    <input type="submit" value="Submit" />
</form>

Note that any client-side validation should only be used for fast feedback to improve the user experience. The actual validation should always be done server-side, as the client-side validation can easily be cheated.

Ingo Bürk
  • 19,263
  • 6
  • 66
  • 100
  • 11
    Ah! Thank you. That was exactly my confusion: I thought the pattern attribute was supposed to disable the user from entering in invalid characters. Thanks everyone for the lightning fast feedback. – levininja Sep 28 '13 at 12:24
  • 2
    +1 Might also add that the square brackets are not required for the pattern :) – Jerry Sep 28 '13 at 12:24
  • 1
    Actually preventing entering data can be a slippery slope anyway, and it can be somewhat annoying, too. For example, `\d{9}` being validated on every keystroke would prevent the user from ever entering anything other than all 9 digits at once (through copy-paste). – Ingo Bürk Sep 28 '13 at 12:26
  • Drop `minlength`, it is pointless and invalid. The markup could also be simplified in a few ways. But the main point is that the code in the answer is basically the same as in the question, so a casual reader will not immediately see what the *problem* was and what the *solution* is. – Jukka K. Korpela Sep 28 '13 at 12:31
  • You're right on the `minlength` attribute, I removed it. If a casual reader decides not to read literally my first sentence, which clearly states the problem and solution, that is up to them. – Ingo Bürk Sep 28 '13 at 12:33
  • You could also add the min requirement to the pattern like this "\d{9,9}" that way, if you don't have at least 9 characters, it won't be valid either. – Leo May 12 '16 at 19:48
  • 1
    @Leo `{9}` is short-hand for `{9,9}`. – Ingo Bürk May 12 '16 at 19:53
  • I thought so.. Any simple attribute to achieve this? – LuckyLuke Skywalker Feb 21 '23 at 23:40
5

The pattern attribute only prevents the form from being submitted if its value does not match. To actually prevent the user from entering invalid text, checkValidity() can be used.

Demo:

let prevVal = "";
document.querySelector('input').addEventListener('input', function(e){
  if(this.checkValidity()){
    prevVal = this.value;
  } else {
    this.value = prevVal;
  }
});
Only enter digits: <input pattern="[0-9]*">
Unmitigated
  • 76,500
  • 11
  • 62
  • 80
0

A revised version to Unmitigated's answer.

let prevVal = "";
document.addEventListener("DOMContentLoaded", function(){
//window.addEventListener('load',function(){
    document.querySelector('INPUT').addEventListener('input', function(e){
      if(this.checkValidity()){
        prevVal = this.value;
      } else {
        this.value = prevVal;
      }
    });    
});