Prevent typing non-numeric in input type number
Asked Answered
M

15

92

Using <input type=number> will cause this.value inside of an event listener to return an empty string if the input is not a valid number. You can see an example of this at http://jsfiddle.net/fSy53/

However, the invalid characters are still displayed in the input.

Is there any way to get the value that is actually displayed, including the invalid characters, from within an event listener?

My ultimate goal is to prevent users from actually typing any non-numeric characters into the field. I need to use type=number so that the numeric virtual keyboard is used by mobile devices. My goal would be to do something like this.value = this.value.replace(/[^0-9.]/g, "") on keyup keypress, but this doesn't work because if an invalid character is typed, reading from this.value returns "".

Mousse answered 13/11, 2013 at 23:14 Comment(8)
I think this was asked before and the answer was no, let me dig it up. EDIT: here is is: #3091310Humpbacked
About the numeric keyboard: There is a new HTML5 attribute inputmode that could be set to numeric to show a numeric keyboard. Unfortunately no browser supports it yet, according to mozillaCapsulate
Note that the issue described happens in Firefox, but not in Chrome. Chrome will prevent non-numeric characters from appearing in an input if type='number' is set.Parlour
Update regarding the inputmode attribute: it is still not supported in any browser by default (see caniuse.com/#search=inputmode), but can optionally be enabled in Firefox by setting the dom.forms.inputmode flag.Parlour
hmmm... isnt "e" the only "invalid" character thats displayed in an type=number??Degrading
Does this answer your question? https://mcmap.net/q/242329/-prevent-input-type-number-from-getting-more-than-one-dot-in-its-value-and-limit-decimals-numbersBrandt
Preventing users from entering a non-numeric character (i.e. BREAKING their keyboard) is not very user friendly. A user friendly approach is to allow them to type and explain what is wrong. A user that is trying to enter a string into a number input will not understand why his keyboard stopped working. I'm surprised how many developers strive to implement this anti user feature. This goes to all blocking behaviors (max-length, patterns), very non user friendly. Not to mention that users do not usually look at their screen while typing.Nakia
@Cesar, I agree. But what about submit-blocking specifically? The pattern is not an input-blocking behavior; a pattern only blocks in upon submit (in Chrome at least). And some input-blocking is browser-controlled; the min/max and min/max-length fields do block input, a possible accessibility problem that is on the browser to fix.Voodoo
F
95

Try preventing the default behaviour if you don't like the incoming key value:

document.querySelector("input").addEventListener("keypress", function (evt) {
    if (evt.which < 48 || evt.which > 57)
    {
        evt.preventDefault();
    }
});
Foliose answered 13/11, 2013 at 23:30 Comment(14)
keypress event is only fired on the document. You'd need to setup a keyboard manager for thisUlyssesumayyad
Not true. keypress fires on the input element, and bubbles to documentFoliose
@Ulyssesumayyad do you have a citation for that? That's contrary to my experience. The OP stated that preventing non-numeric contents is the goal, I think this is the right approach: prevent it before it happeans and don't worry about the .valueReligionism
@GlennLane the problem is that for shift keys such as $ the .which is the same as for the non-shift key and on the virtual keyboards, e.shiftKey is not set to a truthy value. Related: #19964574Mousse
I don't find that behaviour on my browser... $ -> 36, 4 -> 52. Must be a Chrome thing.Foliose
@GlennLane by virtual keyboards I mean on like an iPhone or something. Even if it were a Chrome thing, that's no good. I need to support more browsers than just the one your solution works forMousse
The issue was using keyup -- it records the same key code (or which or whatever it is) based on the key typed. Keypress does seem to work consistently.Mousse
be aware that this blocks "tab" as well in firefox, but not in chromeVines
With this you can't press arrow, backspace etc keys, there is extended solution exists https://mcmap.net/q/46461/-how-to-allow-only-numeric-0-9-in-html-inputbox-using-jqueryAesop
if (isNaN(parseInt(evt.key,10))) { evt.preventDefault(); }Trauma
Unable to backspace with your solution, @TraumaPhotoflood
oninput ------- better to useInterpenetrate
This is a very unreliable solution and I don't understand why it's the accepted answerDeterminer
@Determiner because it's 11 years old and I can't delete itFoliose
H
26

You can accomplish this by preventing the keyPress event from occurring for non-numeric values

e.g (using jQuery)

$('.input-selector').on('keypress', function(e){
  return e.metaKey || // cmd/ctrl
    e.which <= 0 || // arrow keys
    e.which == 8 || // delete key
    /[0-9]/.test(String.fromCharCode(e.which)); // numbers
})

This accounts for all different types of input (e.g. input from the number pad has different codes than the keyboard) as well as backspace, arrow keys, control/cmd + r to reload etc

Hang answered 4/12, 2014 at 16:43 Comment(3)
The arrow key codes are 37 through 40 #20863829Cress
e.which == 46 for dot key if float are neededAuse
Note that there are other ways to insert into an html input, like copy past, drop and autofill so on...Raffarty
O
19

Please note that e.which, e.keyCode and e.charCode are deprecated: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/which

I prefer e.key:

document.querySelector("input").addEventListener("keypress", function (e) {
    var allowedChars = '0123456789.';
    function contains(stringValue, charValue) {
        return stringValue.indexOf(charValue) > -1;
    }
    var invalidKey = e.key.length === 1 && !contains(allowedChars, e.key)
            || e.key === '.' && contains(e.target.value, '.');
    invalidKey && e.preventDefault();});

This function doesn't interfere with control codes in Firefox (Backspace, Tab, etc) by checking the string length: e.key.length === 1.

It also prevents duplicate dots at the beginning and between the digits: e.key === '.' && contains(e.target.value, '.')

Unfortunately, it doesn't prevent multiple dots at the end: 234....

It seems there is no way to cope with it.

Outdare answered 15/3, 2017 at 9:54 Comment(2)
I like this approach. It is clean and works well. One issue with it is that it blocks things like Ctrl+R (reload current page), Ctrl+A, etc. I believe it is safe to add an !e.ctrlKey check.Malayoindonesian
The keypress event is also deprecated. See developer.mozilla.org/en-US/docs/Web/API/Document/… and also developer.mozilla.org/en-US/docs/Web/API/Element/keypress_eventBernete
F
8

The other answers seemed more complicated than necessary so I adapted their answers to this short and sweet function.

function allowOnlyNumbers(event) {
  if (event.key.length === 1 && /\D/.test(event.key)) {
    event.preventDefault();
  }
}

It won't do change the behavior of any arrow, enter, shift, ctrl or tab keys because the length of the key property for those events is longer than a single character. It also uses a simple regular expressions to look for any non digit character.

Ferrocene answered 21/8, 2019 at 19:28 Comment(3)
so what about if somebody wants decimal numbers? such as 10.01? And that doesn't prevent 1.1.1 from submission.Bannasch
pressing CTRL + X won't work with thisYingling
@Yingling Add !e.shiftKey && !e.ctrlKey && !e.metaKey && to the if condition.Khelat
M
4

This solution seems to be working well for me. It builds on @pavok's solution by preserving ctrl key commands.

document.querySelector("input").addEventListener("keypress", function (e) {
  if (
    e.key.length === 1 && e.key !== '.' && isNaN(e.key) && !e.ctrlKey || 
    e.key === '.' && e.target.value.toString().indexOf('.') > -1
  ) {
    e.preventDefault();
  }
});
Microfarad answered 11/4, 2018 at 16:38 Comment(1)
best solution so farAssamese
H
3
inputs[5].addEventListener('keydown', enterNumbers);

function enterNumbers(event) {
  if ((event.code == 'ArrowLeft') || (event.code == 'ArrowRight') ||
     (event.code == 'ArrowUp') || (event.code == 'ArrowDown') || 
     (event.code == 'Delete') || (event.code == 'Backspace')) {
     return;
  } else if (event.key.search(/\d/) == -1) {
    event.preventDefault();
  }
}

in this case, the value of the input field stays intact when a non-number button is pressed, and still delete, backspace, arrowup-down-left-right work properly and can be used for modifying the digital input.

Highbinder answered 3/6, 2017 at 20:11 Comment(0)
S
2

try this one :

  1. current key pressed -> e
  2. if e is not a number -> isNaN(e.key)
  3. when condition is true , so default action should not be taken as it normally would be -> e.preventDefault()
  4. else, return default action... e
input.addEventListener("keypress", function (e) {
  if (isNaN(e.key)) e.preventDefault();
});
Surfperch answered 25/4, 2022 at 13:56 Comment(4)
Could you please explain what your code does and how it solves the OP's Issue?Fermi
any key pressed is equal to (e) parameter , then if e.key is not a number , return preventDefault() , so what is preventDefault() method ? ....tells the user agent that if the event does not get explicitly handled, its default action should not be taken as it normally would be.Surfperch
Thank you for responding, but I actually was hoping you would edit your answer with those details to improve the quality of your post. You will notice that when a user answers a question with 'try this' and a few lines of code, the answers rarely perform wellFermi
you right , sorry.Surfperch
F
1

I will add MetaKey as well, as I am using MacOS

input.addEventListener("keypress", (e) => {
    const key = e.key;
    if (!(e.metaKey || e.ctrlKey) && key.length === 1 && !/\d\./.test(key)) {
        e.preventDefault();
    }
}

Or, you can try !isNaN(parseFloat(key))

Fatness answered 4/4, 2019 at 18:59 Comment(0)
T
1

Update on the accepted answer:

Because of many properties becoming deprecated

(property) KeyboardEvent.which: number @deprecated

you should just rely on the key property and create the rest of the logic by yourself:

The code allows Enter, Backspace and all numbers [0-9], every other character is disallowed.

document.querySelector("input").addEventListener("keypress", ({ key, preventDefault }) => {
  if (isNaN(parseInt(key, 10)) && !['Backspace', 'Enter'].includes(key)) {
      preventDefault();
    }
});

NOTE This will disable paste action

Trauma answered 23/8, 2019 at 7:15 Comment(0)
W
0

Based on Nrzonline's answer: I fixed the problem of the multiple "." at the end of the input by adding a

let lastCharacterEntered

outside of the input and then onKeyPress

e => {
          var allowedChars = "0123456789.";
          function contains(stringValue, charValue) {
            return stringValue.indexOf(charValue) > -1;
          }
          var invalidKey =
            (e.key.length === 1 && !contains(allowedChars, e.key)) ||
            (e.key === "." && contains(e.target.value, "."));
          console.log(e.target.value);
          invalidKey && e.preventDefault();
          if (!invalidKey) {
            if (lastCharacterEntered === "." && e.key === ".") {
              e.preventDefault();
            } else {
              lastCharacterEntered = e.key;
            }
          }
        }
Wounded answered 25/3, 2020 at 10:0 Comment(0)
B
0

I just had the same problem and discovered an alternative solution using the validation API - works without black magic in all major browsers (Chrome, Firefox, Safari) except IE. This solution simply prevents users from entering invalid values. I also included a fallback for IE, which is not nice but works at least.

Context: onInput function is called on input events, setInputValue is used to set the value of the input element, previousInputValue contains the last valid input value (updated in setInputValue calls).

    function onInput (event) {
        const inputValue = event.target.value;

        // badInput supported on validation api (except IE)
        // in IE it will be undefined, so we need strict value check
        const badInput = event.target.validity.badInput;

        // simply prevent modifying the value
        if (badInput === true) {
        // it's still possible to enter invalid values in an empty input, so we'll need this trick to prevent that
            if (previousInputValue === '') {
                setInputValue(' ');
                setTimeout(() => {
                    setInputValue('');
                }, 1);
            }
            return;
        }

        if (badInput === false) {
            setInputValue(inputValue);
            return;
        }

        // fallback case for IE and other abominations

        // remove everything from the string expect numbers, point and comma
        // replace comma with points (parseFloat works only with points)
        let stringVal = String(inputValue)
            .replace(/([^0-9.,])/g, '')
            .replace(/,/g, '.');

        // remove all but first point
        const pointIndex = stringVal.indexOf('.');
        if (pointIndex !== -1) {
            const pointAndBefore = stringVal.substring(0, pointIndex + 1);
            const afterPoint = stringVal.substring(pointIndex + 1);

            // removing all points after the first
            stringVal = `${pointAndBefore}${afterPoint.replace(/\./g, '')}`;
        }

        const float = parseFloat(stringVal);
        if (isNaN(float)) {
            // fallback to emptying the input if anything goes south
            setInputValue('');
            return;
        }
        setInputValue(stringVal);
}
Batey answered 6/5, 2020 at 8:22 Comment(0)
C
0

Prevent typing non-Alphabet in specific input id for pages that have more than one input item.it's usable for Oracle Apex developers --- Append in HTML header of page

<script type="text/javascript">
function validateNumber(event) {
  const activeElmnt = document.activeElement;  
  var keyCode = event.keyCode;
  var excludedKeys = [8, 37, 39, 46];
 
   if ( activeElmnt.id == "input id in HTML page"){
        if (!((keyCode >= 65 && keyCode <= 90) ||
            (keyCode >= 97 && keyCode <= 122) ||
            (excludedKeys.includes(keyCode)))) {
            console.log("alphabets are not allowed");
            event.preventDefault();

  }
}
  console.log("keycode: " + keyCode + "ActiveElemet: "+activeElmnt.id);
}
</script>

-- Append in page HTML Body attribute onkeydown="validateNumber(event);"

Castanets answered 13/9, 2021 at 6:43 Comment(0)
M
0

here is my simple solution simply in this solution u should keep the input type to text so when you use event.target.value you get the full string not only the numbers or an empty string instead so you actually can check if there is a point yet or not. and i didn't use the deprecated properties event.which

isNumber(event) {
      var allowed = "";
      if (event.target.value.includes(".")) {
        allowed = "123456789";
      } else {
        allowed = "123456789.";
      }
      if (!allowed.includes(event.key)) {
        event.preventDefault();
      }
    }

document.getElementById('number').addEventListener('keypress', isNumber);

the HTML 

```

 function isNumber(event) {
      var allowed = "";
      if (event.target.value.includes(".")) {
        allowed = "0123456789";
      } else {
        allowed = "0123456789.";
      }
      if (!allowed.includes(event.key)) {
        event.preventDefault();
      }
      }
      
      document.getElementById('number').addEventListener('keypress',isNumber);
<h3>You can input only numbers and one point (this would be a float or int) </h3>
<input type="text" id="number" />
Mada answered 1/5, 2022 at 0:4 Comment(0)
H
0

This one should work. Only works with integers.

function validateNumberInput(e) {
    if (isNaN(e.key)) {
        e.preventDefault();
    }
}

You can however implement floats with few more lines:

function validateNumberInput(e) {
    if (isNaN(e.key) && e.key !== '.') {
        e.preventDefault();
    } else if (e.key === '.') {
        if (e.target.value.indexOf('.') >= 0) {
            e.preventDefault(); 
        }
    }
}

Finally use it like:

targetInput.addEventListener('keypress', function (e) {
    validateNumberInput(e);
});
Heartthrob answered 17/9, 2022 at 2:52 Comment(0)
S
-2

Try it:

document.querySelector("input").addEventListener("keyup", function () {
   this.value = this.value.replace(/\D/, "")
});
Sanfo answered 13/11, 2013 at 23:26 Comment(1)
In the event the input contains characters the value is cleared and not just the non-digit characters. This is because the value of a numeric box is a floating point number. Therefore (according to the spec) a non-floating point will set the value of the control to ''.Fixture

© 2022 - 2024 — McMap. All rights reserved.