I have a text box and only want to accept numbers and a period "." when using VueJS. Can anyone help with code? I'm new to Vue.
-
7I know its an old question but it was top in Google results. So here is a solution to users with similar problem. I think all solutions here are complicated. The simplest thing to do is to add @input event and replace all non-digits and dot. `this.message.replace(/[^0-9.]/g,'');`. Here is a **[fiddle](http://jsfiddle.net/2c7h4qsm/1/)** to demonstrate. – Kalimah Dec 08 '18 at 10:05
-
3@KalimahApps - allows for multiple dots = problem. – Jquestions Feb 06 '19 at 17:20
-
Seriously, don't read further do what @Kalimah suggests. I had it enabled in 15 secs – DKebler Jan 29 '20 at 23:31
-
@Kalimah I really like your solution. That's what I did firstly, but the problem is when I have multiple text fields which accept only numbers. How can I do it without repeating code? I made one function that worked for all fields using using `event.target.value = event.target.value.replace(/[^0-9]/g, "");` on "@input" event, but when I added v-model (because I need it for different reason), now it doesn't work... Please help. Thanks in advance! – Vasilije Bursac Aug 25 '20 at 20:06
-
1@VasilijeBursac You can use this [codepen](https://codepen.io/aliso1990/pen/eYzdQXy). – Ali Sohrabi Oct 21 '20 at 07:32
-
@AliSohrabi Thank you very much for answer and help! – Vasilije Bursac Oct 22 '20 at 15:54
20 Answers
You can write a Vue method and that method can be called on the keypress event. Check out this fiddle.
Update:
adding source code:
HTML
<div id="demo">
<input v-model="message" @keypress="isNumber($event)">
</div>
Vue.js
var data = {
message: 1234.34
}
var demo = new Vue({
el: '#demo',
data: data,
methods: {
isNumber: function(evt) {
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if ((charCode > 31 && (charCode < 48 || charCode > 57)) && charCode !== 46) {
evt.preventDefault();;
} else {
return true;
}
}
}
});

- 60,438
- 111
- 314
- 488

- 5,030
- 2
- 19
- 33
-
-
-
-
@MuhGhazaliAkbar Did you try the fiddle ? I can type and see that it only allows number and dot. – Deendayal Garg Mar 31 '17 at 10:14
-
8In order to not allow the period change `charCode !== 46` to `charCode === 46` – jeremykenedy Jul 18 '17 at 17:22
-
In order to make it work in Firefox replace `isNumber(event)` to `isNumber` – alexeydemin Jan 03 '18 at 20:27
-
3I implemented this and it works well except for one thing. I had to define event in data or it would throw a console error. I simply added "event: null" and no more errors! – ADP Mar 02 '18 at 16:36
-
7
-
-
This doesn't work at all in Firefox. It also shows the console warning. Replacing isNumber(event) with isNumber($event) as tanathos suggested fixes both problems and works in Chrome and Firefox. – naveed Sep 20 '18 at 02:19
-
5I tried in in your js fiddle, and I can input more than 1 period. It must be 1 only. How to do that? – MONSTEEEER Jan 22 '19 at 02:56
-
6
-
5
-
You better use the following function for VUE JS: ```isNumber(evt) { evt = evt || window.event; let charCode = evt.which || evt.keyCode; if ( charCode > 31 && (charCode < 48 || charCode > 57) && charCode !== 46 ) { evt.preventDefault(); } else { return true; } return false; }``` – EpsilonTal Mar 07 '20 at 21:47
-
-
My solution is more flexible since it's based on `input` event and therefore it handles paste events as well. https://stackoverflow.com/a/64974337/836723 – Maksim Shamihulau Nov 27 '22 at 08:48
You should change your input to type="number"
to more accurately reflect your behaviour. You can then use the built-in Vue.js directive v-model.number
.
Usage:
<input type="number" v-model.number="data.myNumberData"/>

- 2,630
- 2
- 18
- 20
-
4Some browsers have `onScroll` for `type=number`, which increment/decrement values. – Danon Mar 26 '19 at 19:32
-
7Using `type=number` is not always a good solution for numerical input as the browser will style the input box differently and add increment/decrement buttons. – nmg49 Jun 05 '19 at 17:34
-
2this answer work but only one character (E) is allowing to enter. why any reason? – Sudhir K Gupta Jul 04 '19 at 09:43
-
2
-
2This still allows entries with multiple decimal points, such as 1.2.3.4.5 – SteveC Jul 31 '19 at 11:24
-
Use the `step` attribute if you don't want to allow decimal values. And concerning the letter E, [here is the link to a more complete explanation](https://stackoverflow.com/questions/31706611/why-does-the-html-input-with-type-number-allow-the-letter-e-to-be-entered-in#:~:text=HTML%20input%20number%20type%20allows,also%20be%20written%20as%202e5.) – nook Aug 31 '20 at 09:25
-
This was my solution. Most of the answers here have been deprecated. Additionally, input values always return a string, even if you key a number. So because of that, some of the solutions here did not work for me.
In my case I didn't want a decimal point, but I added that into the array for the purpose of this thread.
<b-form-input v-model.number="quantity" @keypress="isNumber($event)" type="number"></b-form-input>
isNumber (evt: KeyboardEvent): void {
const keysAllowed: string[] = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '.'];
const keyPressed: string = evt.key;
if (!keysAllowed.includes(keyPressed)) {
evt.preventDefault()
}
}

- 606
- 6
- 22

- 429
- 4
- 6
-
7
-
3this should be the main answer. most of rest answers uses `event.keyCode` which is depracted – Ali Chraghi Feb 01 '22 at 07:53
-
1
-
As of recently, you can also detect keys like `Backspace` and `Delete` by simply adding them to that list. `event.key` supports that perfectly. – Vahid Amiri Oct 26 '22 at 11:30
-
1
Short and easy understand.
HTML
<input @keypress="onlyNumber" type="text">
VUE JS
onlyNumber ($event) {
//console.log($event.keyCode); //keyCodes value
let keyCode = ($event.keyCode ? $event.keyCode : $event.which);
if ((keyCode < 48 || keyCode > 57) && keyCode !== 46) { // 46 is dot
$event.preventDefault();
}
}

- 753
- 2
- 7
- 19
-
7This way "Backspace" keypress is also not allowed. What if I want to delete previous number and add another? – Tarasovych Nov 06 '18 at 21:20
-
1You can check key code using this code console.log($event.keyCode); //keyCodes value – Mengseng Oeng Apr 06 '19 at 05:04
-
1
-
A simple way to do this in one line:
IsNumber(event) {
if (!/\d/.test(event.key) && event.key !== '.') return event.preventDefault();
}

- 171
- 1
- 8
-
3I dont know about the performance (because of the regex), but this should the one and only answer if you are checking for numbers.... – yooouuri Aug 25 '20 at 14:03
-
2For me works `if (!/^[0-9]+$/.test(event.key) || event.key === '.') return event.preventDefault();` – Tenarius Aug 28 '20 at 09:13
-
`allowDecimalChars(event: KeyboardEvent) { if (/[^.0-9]/.test(event.key)) { event.preventDefault() } }` – broc.seib Sep 26 '20 at 00:35
Here is a better way to handle the specific question asked (numbers and "dots" only) by setting v-restrict.number.decimal using the following directive. It also had some bonus code to support alpha only or alphanumeric. You could also only allow "dots" although I do not know why you would. It will not allow extra characters to "sneak through" if typing fast. It also supports copy/paste, delete, and some other keys users would expect to still work from an input:
Vue.directive('restrict', {
bind (el, binding) {
el.addEventListener('keydown', (e) => {
// delete, backpsace, tab, escape, enter,
let special = [46, 8, 9, 27, 13]
if (binding.modifiers['decimal']) {
// decimal(numpad), period
special.push(110, 190)
}
// special from above
if (special.indexOf(e.keyCode) !== -1 ||
// Ctrl+A
(e.keyCode === 65 && e.ctrlKey === true) ||
// Ctrl+C
(e.keyCode === 67 && e.ctrlKey === true) ||
// Ctrl+X
(e.keyCode === 88 && e.ctrlKey === true) ||
// home, end, left, right
(e.keyCode >= 35 && e.keyCode <= 39)) {
return // allow
}
if ((binding.modifiers['alpha']) &&
// a-z/A-Z
(e.keyCode >= 65 && e.keyCode <= 90)) {
return // allow
}
if ((binding.modifiers['number']) &&
// number keys without shift
((!e.shiftKey && (e.keyCode >= 48 && e.keyCode <= 57)) ||
// numpad number keys
(e.keyCode >= 96 && e.keyCode <= 105))) {
return // allow
}
// otherwise stop the keystroke
e.preventDefault() // prevent
}) // end addEventListener
} // end bind
}) // end directive
To use:
<!-- number and decimal -->
<input
v-model="test"
v-ep-restrict.number.decimal
...
/>
<!-- alphanumeric (no decimal) -->
<input
v-model="test2"
v-ep-restrict.alpha.number
...
/>
<!-- alpha only -->
<input
v-model="test3"
v-ep-restrict.alpha
...
/>
This can be modified to serve as a base for just about any scenario and a good list of key codes is here

- 1,243
- 2
- 20
- 42
-
1I love this answer, but can it be updated to account for keyCode being deprecated? – Trevor Jul 18 '19 at 13:12
I solved issue like yours via vue.js filters. First i created filter - let's say in filters.js file
export const JustDigits = () => {
Vue.directive('digitsonly', (el, binding) => {
if (/[\d\.]+/i.test(el.value)) {
console.log('ok');
} else {
let newValue = el.value.replace(/[a-zA-Z]+/ig, '');
el.value = newValue;
console.log('should fix', newValue);
binding.value = el.value;
}
});
};
Then in the component where this functionality is required i did:
import {
JustDigits
} from './filters';
JustDigits();
And then you are able to use this directive in template:
<input v-model="myModel"
v-digitsonly
type="text"
maxlength="4" class="form-control" id="myModel" name="my_model" />
Please note, that my regex may differ from what you need, feel free to modify it as well as this code line let newValue = el.value.replace(/[a-zA-Z]+/ig, '');
that removes characters from the string. I posted it just to show you one of the possible solutions vue.js provides to solve task like this.

- 586
- 3
- 12
-
if you type more than one letter the second one sometimes goes through. – Yevgeniy Afanasyev May 28 '18 at 02:09
-
You can avoid the fast typing extra characters getting though by wrapping the value in a half second or so debounce (importing from lodash or unserscore) before checking it – D Durham Aug 29 '18 at 02:26
Building on previous solutions, to prevent multiple decimal positions, also pass the v-model to the function:
<input v-model="message" v-on:keypress="isNumber($event, message)">
and modify the isNumber method as follows:
isNumber(event, message) {
if (!/\d/.test(event.key) &&
(event.key !== "." || /\./.test(message))
)
return event.preventDefault();
}
To limit the number of digits after the decimal add the following line into the isNumber method:
if (/\.\d{2}/.test(message)) return event.preventDefault();
The \d{2}
limits the entry of two digits. Change this to \d{1}
to limit to one.
As stated in other answers, this does not prevent the pasting of non-numeric data.

- 644
- 7
- 12
I needed my input to allow only digits, so no e
symbol, plus, minus nor .
. Vue seems funky and doesn't re-trigger @onkeypress
for symbols like dot
.
Here is my solution to this problem:
<input
onkeypress="return event.key === 'Enter'
|| (Number(event.key) >= 0
&& Number(event.key) <= 9"
type="number"
>
I am taking digits only, limiting from 0 to 9, but also I do want enable form submit on Enter, which would be excluded with the above approach - thus the enter.

- 3,415
- 4
- 30
- 49
-
2There's a missing parenthesis in the condition, but works great! :thumbs-up: – Eleazar Resendez Feb 11 '20 at 17:17
-
1
You can handle this via simple html
<input type="number">
and in your app.css
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* this is for Firefox */
input[type=number] {
-moz-appearance: textfield;
}
Style code will remove ugly arrows from your number input field and yes it accepts dots

- 107
- 7
@Kalimah answer didn't work for me, but I liked the idea of using regex. In my case I needed to filter out any non-digit character, including dots. The below code worked for me, Vue 2.6.
<input type="text" v-model="variable" @input="cleanVariable" />
methods: {
cleanVariable(event) {
this.variable = event.target.value.replace(/[^0-9]/g, "");
}

- 193
- 1
- 4
- 12
Why not using an external mask lib like vue-the-mask or cleave.js?
For example, with vue-the-mask you can easily use theirs directive like this:
<input type="text" name="some-name" id="some-id" v-model="some.value" v-mask="'##.##.##.##.###'">

- 863
- 2
- 11
- 25
You can use this library https://www.npmjs.com/package/vue-input-only-number
import onlyInt, { onlyFloat } from 'vue-input-only-number';
Vue.use(onlyInt);
Vue.use(onlyFloat);
<input type="text" v-int>
<input type="text" v-float>

- 2,650
- 26
- 24
There is input
event which is more powerful/flexible than keypress
, keydown
or change
that reacts on any type of change: program or user type such as key presses or paste events.
// Initial input state
let prevValue = ''
let prevSelectionStart = 0
function allowNumbersOnly(event) {
const input = event.target
let value = event.target.value
// Check if value is number
let isValid = +value == +value
if (isValid) {
// preserve input state
prevValue = value
prevSelectionStart = input.selectionStart
} else {
// restore previous valid input state.
// we have to fire one more Input event in order to reset cursor position.
var resetEvent = new InputEvent('input')
input.value = prevValue
input.selectionStart = prevSelectionStart
input.selectionEnd = prevSelectionStart
input.dispatchEvent(resetEvent)
}
}
<input type="text" oninput="allowNumbersOnly(event)">

- 1,219
- 1
- 15
- 17
Just evaluate if is nan and now you can prevent default
<input @keypress="isNumber">
isNumber (val) {
if (isNaN(Number(val.key))) {
return val.preventDefault();
}
}

- 4,292
- 1
- 24
- 41
-
1This would be a great answer if it wouldn't also disable `delete` and `enter` keys. – Artur Müller Romanov Nov 22 '22 at 12:55
The problem with type="number"
and min="1"
is that it allows typing or pasting the -
sign, the e
sign and the +
sign.
The problem with the Math.abs(value)
is that it replaces the whole typed in number with 0
, which we don't want and is very frustrating.
The e.keyCode
is very unreadable and deprecated.
The pure HTML method doesn't work in this case, you have to use JavaScript.
Remove the type="number"
and do this:
function inputNumberAbs() {
var input = document.getElementsByTagName("input")[0];
var val = input.value;
val = val.replace(/^0+|[^\d.]/g, '');
input.value = val;
}
<input oninput="inputNumberAbs()">
Regex explanation:
^0+
removes all 0s from beginning
|
OR operator
[^\d].
remove everything that is^
(NOT) a\d
(NUMBER) or a.
(PERIOD)
This prevents the user to type or paste any of the not defined characters, like e, -, +,
and all other characters that are not numbers.
If you don't need decimal numbers just remove .
from regex.

- 61
- 3
I cannot find the perfect solution because some work for input but not for copy&paste, some are the other way around. Below's solution works for me. It prevents negative numbers, typing "e", copy&paste "e" text.
I use mixin so I can be reused anywhere.
const numberOnlyMixin = {
directives: {
numericOnly: {
bind(el, binding, vnode) {
// console.log(el, binding);
// this two prevent from copy&paste non-number text, including "e".
// need to have both together to take effect.
el.type = 'number';
el.addEventListener('input', (e) => {
// console.log('input', e);
// console.log(el.validity);
return el.validity.valid || (el.value = '');
});
// this prevents from typing non-number text, including "e".
el.addEventListener('keypress', (e) => {
let charCode = (e.which) ? e.which : e.keyCode;
if ((charCode > 31 && (charCode < 48 || charCode > 57)) && charCode !== 46) {
e.preventDefault();
} else {
return true;
}
});
}
}
},
};
export {numberOnlyMixin}
In your component, add to your input.
<input v-model="myData" v-numericOnly />

- 3,098
- 1
- 35
- 42
-
1POTENTIAL MEMORY LEAK! Is this solution production ready? I think you need to unbind event listeners when the element leaves the DOM. – Emeke Ajeh Feb 19 '20 at 09:34
-
I believe creating a directive is the correct approach, although this implementation is more complex than it should be. If you're concerned about memory leaks, you can remove the listener on the directive's `unbind` event. JavaScript seems to take care of that automatically though. – Parziphal Apr 04 '22 at 15:14
<v-text-field class='reqField' label="NUMBER" @keypress="isNumber($event)"></v-text-field>
methods: {
isNumber: function(evt) {
evt = (evt) ? evt : window.event;
var charCode = (evt.which) ? evt.which : evt.keyCode;
if (charCode > 31 && (charCode < 48 || charCode > 57) && (charCode != 9)) {
evt.preventDefault();
} else {
return true;
}
`enter code here`
},
}

- 85
- 6
I use watcheffect() and regex for this. This way, it works with copy-paste as well.
<template>
<input type="text" v-model="data">
</template>
<script>
import { ref, watchEffect } from 'vue'
export default {
setup() {
const data = ref('')
watchEffect(() => {
data.value = data.value.replace(/[^\.0-9]/g, '')
})
return { data }
}
}
</script>

- 11
- 1
You can use the number type in it:
<input type="number" class="yourCssClass" placeholder="someText" id="someId" />
and then, add the CSS required to remove the up/down spinners:
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}

- 29
- 1
- 1
- 5
-
This answer is insufficient. It doesn't handle `e` in Chromium-based browsers. Also, browsers such as Firefox don't block non numeric chars when input is type number. You can check this using MDN documentation while running Firefox: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number – derekbaker783 Feb 12 '22 at 12:20