If you ever have an HTML <input>
element for numbers — <input type="number" />
— you might notice that it defaults to accepting integers as values, and increments and decrements by one. There’s ways to make it accept, increment by, and decrement by decimal values too.
The step
attributepermalink
When you add the step
attribute to your <input>
element, it specifies how granular the numbers can be in the input.
If you truly don’t care what the value is, you can use step="any"
like so:
- Code language
- html
<input id="number" type="number" value="42" step="any" />
See the Pen HTML Number Input with step='any' by piccalilli (@piccalilli) on CodePen.
Your users can then input any number their heart desires, even if it’s several decimal places deep.
But, let’s say you want it to be a monetary value, for example, only to two decimal places. Then, you make step="0.01"
.
- Code language
- html
<input id="number" type="number" value="3.14" step="0.01" /> <!-- 3.15 valid, 3.14159 invalid -->
Try setting a value of three decimal places in this demo to see how it fails validation.
See the Pen HTML Number Input with step='0.01' by piccalilli (@piccalilli) on CodePen.
Not too bad, right? You can even get funky with it and give it a really specific number value, and if the user clicks up and down with the input box controls, it’ll go up by that amount:
- Code language
- html
<input id="number" type="number" value="3.14" step="3.14" /> <!-- 9.42 valid, 9.43 invalid -->
See the Pen HTML Number Input with step='3.14' by piccalilli (@piccalilli) on CodePen.
Can I use pattern
to do the same thing?permalink
Theoretically yes. If you haven’t seen the pattern
attribute, you can use it in your HTML to do regex pattern matching. It can be used for decimal places too. Should you use it for that? Probably not, especially when step
is right there, waiting to be used. But you can use it.
For example, you can use pattern
to match a one or two-digit number with two decimal places after it:
- Code language
- html
<input type="number" pattern="\d{1,2}(\.\d{2})?" /> <!-- 12.34 valid, 123.4 invalid -->
Try typing in a number with more than two decimal places or three numbers before the decimal point to see how it fails validation.
See the Pen HTML Number Input with pattern='\d{1,2}(\.\d{2})?' by piccalilli (@piccalilli) on CodePen.
…it’s not cute, but it does get the job done if you really want this kind of behavior. The pattern
attribute is definitely more suitable for text-based inputs — like an email address — rather than numerical ones. The pattern
attribute doesn’t provide the same UI controls that step
gives you either.
This approach of using pattern
is particularly good for adhering to specific patterns, like “a number that is exactly 4 digits” (pattern="[0-9]{4}"
), rather than limiting input data to a certain number of decimal places. But, the max
attribute set to 9999
will do the same thing, and it’s more semantic.
What happens when I break the step
or pattern
?permalink
With both step
and pattern
, your <input>
element will match the :invalid
pseudo-class in CSS, so you can style it, and there’s often a browser-native validation message as well when a user tries to submit the form.
If your users type in an invalid value anyway, you can still run JavaScript on it and see what the value
is. Sometimes the browser rounds the number to the closest one that will fit. I say “sometimes” because… It Depends™.
See the Pen HTML Number Inputs, with JavaScript by piccalilli (@piccalilli) on CodePen.
In this demo, you can see that some of the initial values in the number inputs are valid, with suggestions on how to change them to see how the browser rounds things. The “raw” value in the input is what you see in the input, but the “valid” value is what the browser might be accepting instead.
Wrapping uppermalink
You should use step
for controlling numeric increments because it’s designed specifically to do that and the browser provides better UI controls for it natively. The step
attribute is more mathematically based, too, instead of text-pattern based. It also works for other numeric input types like range
and works really well when paired with the min
and max
attributes.
Use pattern
for more complex pattern validation beyond the number of decimal places you want! But, remember that it doesn’t have built-in incrementing and decrementing controls, and the validation is done based on text-pattern matching.