Note: This is an updated answer. Comments below refer to an old version which messed around with keycodes.
JavaScript
Try it yourself on JSFiddle.
You can filter the input values of a text <input>
with the following setInputFilter
function (supports Copy+Paste, Drag+Drop, keyboard shortcuts, context menu operations, non-typeable keys, the caret position, different keyboard layouts, and all browsers since IE 9):
// Restricts input for the given textbox to the given inputFilter function.
function setInputFilter(textbox, inputFilter) {
["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop"].forEach(function(event) {
textbox.addEventListener(event, function() {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (this.hasOwnProperty("oldValue")) {
this.value = this.oldValue;
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
} else {
this.value = "";
}
});
});
}
You can now use the setInputFilter
function to install an input filter:
setInputFilter(document.getElementById("myTextBox"), function(value) {
return /^\d*\.?\d*$/.test(value); // Allow digits and '.' only, using a RegExp
});
See the JSFiddle demo for more input filter examples. Also note that you still must do server side validation!
TypeScript
Here is a TypeScript version of this.
function setInputFilter(textbox: Element, inputFilter: (value: string) => boolean): void {
["input", "keydown", "keyup", "mousedown", "mouseup", "select", "contextmenu", "drop"].forEach(function(event) {
textbox.addEventListener(event, function(this: (HTMLInputElement | HTMLTextAreaElement) & {oldValue: string; oldSelectionStart: number | null, oldSelectionEnd: number | null}) {
if (inputFilter(this.value)) {
this.oldValue = this.value;
this.oldSelectionStart = this.selectionStart;
this.oldSelectionEnd = this.selectionEnd;
} else if (Object.prototype.hasOwnProperty.call(this, 'oldValue')) {
this.value = this.oldValue;
if (this.oldSelectionStart !== null &&
this.oldSelectionEnd !== null) {
this.setSelectionRange(this.oldSelectionStart, this.oldSelectionEnd);
}
} else {
this.value = "";
}
});
});
}
jQuery
There is also a jQuery version of this. See this answer.
HTML 5
HTML 5 has a native solution with <input type="number">
(see the specification), but note that browser support varies:
- Most browsers will only validate the input when submitting the form, and not when typing.
- Most mobile browsers don't support the
step
, min
and max
attributes.
- Chrome (version 71.0.3578.98) still allows the user to enter the characters
e
and E
into the field. Also see this question.
- Firefox (version 64.0) and Edge (EdgeHTML version 17.17134) still allow the user to enter any text into the field.
Try it yourself on w3schools.com.
Best Solution
Don't do it with setting style attributes. Do it by using CSS classes. I would also recommend using a Javascript library to handle this. It just makes the code cleaner.
Removing CSS attributes is problematic because you don't always know what they should be set back to. Adding and removing classes just... works.
You can have multiple classes per element so there's really no argument against doing it this way (imho).
I'm used to jQuery so my example is with that.
Wrong way:
Right way: