459

I have a <input type="number"> and I want to restrict the input of the users to purely numbers or numbers with decimals up to 2 decimal places.

Basically, I am asking for a price input.

I wanted to avoid doing regex. Is there a way to do it?

<input type="number" required name="price" min="0" value="0" step="any">
Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
nubteens
  • 5,462
  • 4
  • 20
  • 31
  • 2
    type="number" doesn't have wide browser support. It is better to just use a textbox with some javascript to make sure that you get the desired input. – www139 Dec 03 '15 at 03:56
  • 7
    Yeah, but inputs fall back to `type="text"` anyways, so what does it matter? – Ultimater Dec 03 '15 at 03:57
  • 2
    Possible duplicate of [Is there a float input type in HTML5?](https://stackoverflow.com/questions/19011861/is-there-a-float-input-type-in-html5) – OhadR Sep 02 '19 at 10:01
  • /^\d+\.\d{2,2}$/ worked for me to require 0.00 – ZStoneDPM Oct 30 '19 at 23:35
  • Does this answer your question? [JavaScript displaying a float to 2 decimal places](https://stackoverflow.com/questions/3163070/javascript-displaying-a-float-to-2-decimal-places) – Hardik Chapla Sep 20 '22 at 11:37

18 Answers18

651

Instead of step="any", which allows for any number of decimal places, use step=".01", which allows up to two decimal places.

More details in the spec: https://www.w3.org/TR/html/sec-forms.html#the-step-attribute

Michael Benjamin
  • 346,931
  • 104
  • 581
  • 701
  • 186
    This is not the correct answer. step only governs what happens when you click or press up and it does not restrict anything. – Ini Jun 05 '18 at 22:47
  • 1
    @Michael_B regardless of what the spec hopes for, this is fairly trivial to test: https://jsfiddle.net/9hvm0b5u still allows more than 2 decimals to be input. The steps only govern what the +/- buttons move the amount by. (Chrome) – Nathan Jun 23 '18 at 18:12
  • 5
    @Michael_B the user is not prevented from typing out a number such as `500.12345` in any of the inputs, perhaps our understanding of the requirements is different. – Nathan Jun 23 '18 at 18:24
  • 1
    Using a decimal without the integer part (a 0 before the decimal point) will cause issues in some browsers. Better to stick to something like step="0.01" – Bruce Jun 12 '19 at 23:29
  • 7
    It should be noted that, while the user may type any number of digits after the decimal place, most browsers will not allow the submission of the form with an invalid value and the CSS selectors `:valid` and `:invalid` are applied as expected. – Andrew Dinmore Jun 13 '19 at 17:29
  • 2
    @Nathan, it is also trivial to test browser validation. Try submitting a value with more than 2 decimal places: https://jsfiddle.net/4yesgn7b/ – imclean Mar 09 '20 at 23:30
  • 4
    @Ini According to the linked spec (and MDN's docs), the `step=""` attribute is used for both the up/down arrows but also for built-in client-side validation (the orange exclamation mark popup that was added to Chrome a couple of years ago, Firefox also supports attribute-based (scriptless) client-side validation). – Dai Sep 28 '20 at 00:22
  • 5
    This is the correct answer because step="0.01" not only validates the decimal precision but also allows the user to insert decimal values in place of default integer – Farhan Ibn Wahid Jan 11 '21 at 06:07
105

In case anyone is looking for a regex that allows only numbers with an optional 2 decimal places

^\d*(\.\d{0,2})?$

For an example, I have found solution below to be fairly reliable

HTML:

<input name="my_field" pattern="^\d*(\.\d{0,2})?$" />

JS / JQuery:

$(document).on('keydown', 'input[pattern]', function(e){
  var input = $(this);
  var oldVal = input.val();
  var regex = new RegExp(input.attr('pattern'), 'g');

  setTimeout(function(){
    var newVal = input.val();
    if(!regex.test(newVal)){
      input.val(oldVal); 
    }
  }, 1);
});
Weston Ganger
  • 6,324
  • 4
  • 41
  • 39
  • 3
    What's the purpose of having the setTimeout()? – Derek Nov 04 '18 at 15:33
  • 2
    @Derek. I assume it's so the regex.test doesn't block the DOM. Lookup this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop – christo8989 Feb 05 '19 at 21:16
  • 3
    @Derek I can only assume the `setTimeout()` is to wait for the `keydown` event to complete before setting the `newVal` (otherwise it'll be the same as the `oldVal`). However, with a timeout of 0, it's pointless and doesn't work as both values are often the same (in Firefox). If you set it to 1, for instance, it works fine. – alstr Feb 11 '20 at 16:34
  • So, you rollbacked my edit in two different posts with a reason "unapproved edit degrades answer's formatting quality". Can you please explain how is my edit unapproved and how exactly does it degrade the answer's quality? (IMO, it improves it, since people could run the code directly from the post and they don't need to go to JSFiddle). – double-beep Feb 14 '20 at 20:51
  • 1
    The ^\d*(\.\d{0,2})?$ regex would allow an input that ends with a dot like this: 122. A slightly better regex would be this: ^\d*(\.\d{1,2})?$ – Veselin Vasilev Sep 02 '20 at 09:02
  • I was just looking for regex. Thanks – Abhishek Kumar Feb 06 '21 at 17:47
  • 1
    try magical **setTimeout(function(){....},1);** instead – Berker Yüceer Jul 10 '21 at 12:53
  • For React I used the pattern, then I used this answer https://stackoverflow.com/a/43688362/582309 to check that the field had a valid input before updating the controlled value. Which is just checking if (evt.target.validity.valid) { update the field } whenever the value is changed. – JoshJoe Aug 02 '21 at 15:42
  • @VeselinVasilev, I think you're missing a little detail here. Typing is sequential, and I don't think anyone on this planet expects to have to type multiple digits before being able to place a decimal point. We're talking about what _behavior is allowed_, not _what input is valid_. – Gust van de Wal Mar 08 '22 at 09:41
  • ^\d*(\.\d{1,2})?$ Is not good because you can't type a `.` when you are inserting your number , unless you click left arrow once or twice then type it.Because if you want for example to enter `100.25` you need to type `100.` then `100.2` then `100.25` , but remumber ? `100.` is not possible in that regex. – Yasser CHENIK Mar 29 '22 at 11:16
38

For currency, I'd suggest:

<div><label>Amount $
    <input type="number" placeholder="0.00" required name="price" min="0" value="0" step="0.01" title="Currency" pattern="^\d+(?:\.\d{1,2})?$" onblur="
this.parentNode.parentNode.style.backgroundColor=/^\d+(?:\.\d{1,2})?$/.test(this.value)?'inherit':'red'
"></label></div>

See http://jsfiddle.net/vx3axsk5/1/

The HTML5 properties "step", "min" and "pattern" will be validated when the form is submit, not onblur. You don't need the step if you have a pattern and you don't need a pattern if you have a step. So you could revert back to step="any" with my code since the pattern will validate it anyways.

If you'd like to validate onblur, I believe giving the user a visual cue is also helpful like coloring the background red. If the user's browser doesn't support type="number" it will fallback to type="text". If the user's browser doesn't support the HTML5 pattern validation, my JavaScript snippet doesn't prevent the form from submitting, but it gives a visual cue. So for people with poor HTML5 support, and people trying to hack into the database with JavaScript disabled or forging HTTP Requests, you need to validate on the server again anyways. The point with validation on the front-end is for a better user experience. So as long as most of your users have a good experience, it's fine to rely on HTML5 features provided the code will still works and you can validate on the back-end.

Weston Ganger
  • 6,324
  • 4
  • 41
  • 39
Ultimater
  • 4,647
  • 2
  • 29
  • 43
  • 5
    According to [MDN](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/number#Pattern_validation), `pattern` doesn't work for `input type=number`: ` elements do not support use of the pattern attribute for making entered values conform to a specific regex pattern. The rationale for this is that number inputs can't contain anything except numbers, and you can constrain the minimum and maximum number of valid digits using the min and max attributes, as explained above.` – izogfif Mar 15 '18 at 10:19
  • 1
    @izogfif Good note. Also note I actually noted you don't need both and provided three ways: Step, pattern, and onblur. My rationale at the time was if a browser chokes on one for some reason it has the other. Probably safe to rely on step these days for frontend validation. – Ultimater Mar 20 '18 at 05:08
32

Step 1: Hook your HTML number input box to an onchange event

myHTMLNumberInput.onchange = setTwoNumberDecimal;

or in the HTML code

<input type="number" onchange="setTwoNumberDecimal" min="0" max="10" step="0.25" value="0.00" />

Step 2: Write the setTwoDecimalPlace method

function setTwoNumberDecimal(event) {
    this.value = parseFloat(this.value).toFixed(2);
}

You can alter the number of decimal places by varying the value passed into the toFixed() method. See MDN docs.

toFixed(2); // 2 decimal places
toFixed(4); // 4 decimal places
toFixed(0); // integer
Robbie JW
  • 729
  • 1
  • 9
  • 22
Sachin Sudhakar Sonawane
  • 1,865
  • 1
  • 22
  • 37
19

Try this for allowing only 2 decimal in input type

<input type="number" step="0.01" class="form-control"  />

Or Use jQuery as suggested by @SamohtVII

$( "#ELEMENTID" ).blur(function() {
    this.value = parseFloat(this.value).toFixed(2);
});
Nilesh Gajare
  • 6,302
  • 3
  • 42
  • 73
11

just adding step=".01", sorted my issue.

<input type="number" class="form-control" name="price" step=".01">
lwegaba
  • 121
  • 1
  • 6
6

I found using jQuery was my best solution.

$( "#my_number_field" ).blur(function() {
    this.value = parseFloat(this.value).toFixed(2);
});
SamohtVII
  • 137
  • 2
  • 12
4

I had the same requirement but after checking all these answers I realized there is no inbuilt support to block users from typing a particular number of decimal points. step="0.01" is useful when validating the input for a decimal number but still it will not block users from typing any decimal. In my case, I wanted a solution which will prevent user from entering invalid decimal. So I created my own custom JavaScript function which will enforce user any decimal rule. There is a slight performance issue but for my scenario it is okay to have a very small delay to make sure that user is not typing invalid decimal places. It might be useful for someone who wanted to prevent user from typing invalid decimal value on the input.

You can use this solution with step="0.01" if you want. You can use the below function on your element oninput event. If performance is critical for you, then think to use this on onchange event rather than oninput. And please specify maximum number of decimal places allowed in the input in data-decimal attribute. it can have values from 0 to any number.

function enforceNumberValidation(ele) {
    if ($(ele).data('decimal') != null) {
        // found valid rule for decimal
        var decimal = parseInt($(ele).data('decimal')) || 0;
        var val = $(ele).val();
        if (decimal > 0) {
            var splitVal = val.split('.');
            if (splitVal.length == 2 && splitVal[1].length > decimal) {
                // user entered invalid input
                $(ele).val(splitVal[0] + '.' + splitVal[1].substr(0, decimal));
            }
        } else if (decimal == 0) {
            // do not allow decimal place
            var splitVal = val.split('.');
            if (splitVal.length > 1) {
                // user entered invalid input
                $(ele).val(splitVal[0]); // always trim everything after '.'
            }
        }
    }
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<input type="number" data-decimal="0" oninput="enforceNumberValidation(this)" placeholder="No decimal places" value="" />
<input type="number" data-decimal="2" oninput="enforceNumberValidation(this)" placeholder="2 decimal places" value="" />
<input type="number" data-decimal="5" oninput="enforceNumberValidation(this)" placeholder="5 decimal places" value="" />

I might use RegExp to identify invalid value but I have to revert the change in the input as well. So I decided to not use RegExp.

Abhilash Augustine
  • 4,128
  • 1
  • 24
  • 24
2

This is the solution I've came up with which also stops the user from typing in more that 2 decimals, which a lot of the solutions mentioned above, don't protect against

html:

<input autocomplete="off" type="number" id="priceField" step=".01" min="0" onkeypress="return priceCheck(this, event);"

Javascript:

function priceCheck(element, event) {
    result = (event.charCode >= 48 && event.charCode <= 57) || event.charCode === 46;
    if (result) {
        let t = element.value;
        if (t === '' && event.charCode === 46) {
            return false;
        }
        let dotIndex = t.indexOf(".");
        let valueLength = t.length;
        if (dotIndex > 0) {
            if (dotIndex + 2 < valueLength) {
                return false;
            } else {
                return true;
            }
        } else if (dotIndex === 0) {
            return false;
        } else {
            return true;
        }
    } else {
        return false;
    }
}
Yonoss
  • 1,242
  • 5
  • 25
  • 41
2

Quoting Mozilla Doc

e.g. step="0.01" to allow decimals to two decimal places

therefore, step="0.01" does the job. step="0.001" allows 3 decimals, step="0.0001" allows 4 decimals etc.

The up and down arrow button on the input:number field also reflexing on the above settings.

e.g. clicking the up button will increase by 1 with step="any", but increase 0.1 with step="0.1"

Max Ma
  • 1,060
  • 9
  • 15
0

Use this code

<input type="number" step="0.01" name="amount" placeholder="0.00">

By default Step value for HTML5 Input elements is step="1".

Obaidul Haque
  • 916
  • 11
  • 18
0

I had a strange editing experience with some of these solutions. This seems to work pretty well from a user's perspective (only intervene when necessary):

function handleNumberChanged (e) {
    const fixed = parseFloat(e.target.value).toFixed(2).toString()
    if (fixed.length < parseFloat(e.target.value).toString().length)
      e.target.value = fixed
}
TreeAndLeaf
  • 1,064
  • 1
  • 13
  • 15
-1

Only 3 decimal point input value in textbox using Javascript.

<input type="text" class="form-control" onkeypress='return AllowOnlyAmountAndDot(this,event,true);/>

function AllowOnlyAmountAndDot(id, e, decimalbool) {    
    if(decimalbool == true) {   
        var t = id.value;
        var arr = t.split(".");
        var lastVal = arr.pop();
        var arr2 = lastVal.split('');
        if (arr2.length > '2') {
            e.preventDefault();
        } 
    }
}
Suhaib Janjua
  • 3,538
  • 16
  • 59
  • 73
-1

On Input:

<input type="number" name="price" id="price" required>

On script:

$('#price').on('change', function() {
    var get_price = document.getElementById('price').value;
    var set_price = parseFloat(get_price).toFixed(2);
    $('input[name=price').val(set_price);
})
-1

This question has been already answer but you can allow decimals with the step attribute. you can read more about it here: Allow-decimal-values

Wilmar Arias
  • 186
  • 8
-2
  <input type="number" class="form-control" id="price" oninput="validate(this)" placeholder="Enter price" name="price" style="width:50%;">

  var validate = function(e) {
      var t = e.value;
      e.value = (t.indexOf(".") >= 0) ? (t.substr(0, t.indexOf(".")) + t.substr(t.indexOf("."), 3)) : t;
  }
Hussain
  • 106
  • 8
-4

You can use this. react hooks

<input
                  type="number"
                  name="price"
                  placeholder="Enter price"
                  step="any"
                  required
                />
-7

just write

<input type="number" step="0.1" lang="nb">

lang='nb" let you write your decimal numbers with comma or period

  • "lang='nb' let you write your decimal numbers with comma or period" Can't speak for anything else, but that doesn't work in Chrome for me. – Andrew Dinmore Jun 13 '19 at 17:46