[Ed. note: While we take some time to rest up over the holidays and prepare for next year, we are re-publishing our top ten posts for the year. Please enjoy our favorite work this year and we’ll see you in 2023.]
I won’t pretend to be the expert on all things related to forms. However I will say this: of all the difficult, unconventional, and unusual requirements I’ve been asked to deliver over the past 15 years, most of those tasks revolved around building forms. Each one presented a challenge that required some sort of outside-the-box or non-standard solution. I’ve learned a lot of ways to overcome those challenges: what you should do, and more importantly, what you should not do when trying to meet those challenges.
Of all the things that I’ve learned about what not to do, one of the easiest and best pieces of advice I can share is this: unless the use case is drop-dead simple, you should avoid using the number input.
I’ve seen so many forms that I felt compelled to build my own form builder that could handle at least some of the more challenging requests without the hassle of writing code from scratch every time. Keenforms is a drag-and-drop form builder with a no-code rules engine. It makes it easier to create dynamic and conditional functionality without having to write code from scratch.
Recently I got some feedback about Keenforms, and the criticism I heard the most was the fact that Keenforms does not use the <input type="number" />.* We do have an input that’s labeled as a number, but when you add it to your form, it actually renders as <input type="text" />.
*Please note that Keenforms actually does use the number input inside our app. However, we only use it in the dashboard and for only the simplest inputs.
The pro-number input crowd has legitimate concerns, primarily around accessibility. A number input has native increment/decrement buttons. It has built-in validation to verify it is a number. Certain mobile devices will show a number keypad instead of the full keyboard, making it easier to enter data. Using the number input makes it easier for screen readers as well.
It should be noted I am not alone in the anti-number input camp. The UK Government posted an article detailing some of the problems related to the number input.
The thing is, the issues cited in that article weren’t even the primary reasons why I decided to avoid it. After receiving that feedback on Keenforms, it occurred to me that there are quite a few programmers out there who are completely unaware of the problems the number input presents. The list isn’t long, but the issues are rather jaw-dropping. So here’s a short list of all the horrible things about the number input (at least the ones that I know about) that every developer should know:
- When the number input contains an invalid value and you retrieve the value, you get a blank string.
- Valid numbers include more than just digits (i.e,. scientific notation like the letter e).
- The min/max attributes can easily be bypassed.
- Different browsers accept different characters.
When the number input contains an invalid value and you retrieve the value, you get a blank string
There are a couple of ways you might go about retrieving the value. It could be on an event listener, which would store the field value in event.target.value. Or you could get it through the DOM element. Either way when the number is invalid you can’t get the actual value that appears on screen in the <input type="number"> field:
const numberInput = document.getElementById('id_here'); console.log(numberInput.value); // will return empty string if invalid
If you are building a form that requires conditional validations or calculations, it is hard to understate just how big of a problem this is. The fact that the number input will allow a user to enter an invalid number value but not actually retrieve that invalid value (getting a blank string instead), makes the kind of validation I routinely get asked to deliver impossible.
If you are just using a number input for someone’s age or the quantity of a product, this might not seem like that big of a problem. However, consider an example of a form I was tasked with building where the number input either affects or is affected by other inputs, such as a life insurance form with the following requirements:
- A number input for the quantity of dependents. The number value will determine the quantity of nested forms for each dependent.
- A number input for each household member that indicates the percentage this person would receive in the event of a payout. If the quantity of dependents is one, then this particular input would be hidden and automatically set to 100. If the quantity is greater than 1, then the input should be visible, and have a value of no less than 0.01, and contain a value less than 100.
- A hidden number input that would sum total the percentage of each dependent listed, validating that the subtotal is exactly 100.
Valid numbers are more than digits
This is the flipside of the invalid number value issue: the number input allows you to enter values that are technically acceptable numbers, but there is a good chance you don’t want them and didn’t anticipate that they could be considered “valid.”
Chances are likely that you used the input type="number" because you expected an integer to represent age or quantity. However, the number input will allow for scientific notation values; for example, 2.3e4, which represents 2.3 times 10 to the power of 4, or 23,000. If the number input value grows large enough, some browsers will automatically convert your input into exponential notation.
Different browsers accept different characters
All browsers are not the same. Let’s start with the best case scenarios.
Chrome and (surprise!) Microsoft Edge
The following characters are permitted (based on my hastily-done first-hand testing);
- Numbers 0-9
- Decimal point
- “-” (for negative values)
- characters “+” and “e” for exponential notation
Firefox and Safari
There are no limits whatsoever. You can type whatever you want.
All of these browsers will show a built-in popup to indicate that the value you’ve entered is not a valid number, and the Submit button will not work without the user fixing those input values. The built-in validation is visually inconsistent to whatever UX when you are building for your app. As a programmer, you might find this acceptable, but there’s a good chance your designer and/or product manager will not.
Min/max limits can be bypassed
The ability to set the minimum and maximum number values in the number input is a nice feature to have. The increment/decrement buttons will keep the number value within these range parameters. However, you cannot completely trust it to prevent out of range values; it is possible to copy/paste a value beyond those limits.
<input type="number" min="1" max="10" />
If this seems petty, I want you to know I totally agree with you. But it’s not always my call.
Imagine a software tester finds this issue and logs a bug. Imagine the product manager hears about the bug. Imagine discussing this bug during sprint planning, but then pleading your case to that same product manager: “This is an edge case and the number will still be validated on the back end.” And besides, you said this was MVP and this “bug” is actually standard behavior of the number input. Imagine losing that battle and having to fix it anyway.
The bottom line is that it’s not always the developer’s choice, and the number input is not your friend.
What to use instead of number inputs
Before I go into detail about when to use the number input, it’s important to establish something that many experienced programmers know, but which is worth repeating; You should only use the number input when dealing with mathematically relevant numeric values, i.e. the quantity of a product or someone’s age. That means you never use the number input for things like ZIP codes, phone numbers, social security numbers, etc.
On to the more interesting stuff. Whether to use the number input must be decided on a case-by-case basis, and the calculus will change based on requirements, risks, and stakeholders.
If you need a number input that has no conditional validation (i.e. number is always within a certain range of min/max) and has no relationship with any other inputs on the form, then using the number input is not a big deal. As mentioned, Keenforms does use the number input for the position value of a form attribute. The risks and consequences of a user wanting to do something malicious (like putting invalid number on the position value) to their own form is low enough that it’s a worthwhile tradeoff.
Make sure the stakeholders are aware of this issue of visual inconsistencies across different browsers as well as inconsistencies of whatever messaging you are using to indicate invalid number input values.
If you are dealing with conditional validation or that number is being used elsewhere for a calculation, that’s when you need to ditch the number input. There are a couple of options on how to deal with this issue:
The Gov.UK article mentions a possible solution: Using <input type="text" inputmode="numeric" pattern="[0-9]*"> is a nice option for integers, but it won’t work for floating point decimal numbers.
That is not to advocate for sacrificing all accessibility for the sake of advanced requirements, visual consistency, and ease of use. I recently spoke with Avram Sand from Access Armada to discuss some of the problems related to the number input.
“The purpose of digital accessibility is to ensure that your forms are understandable and usable for everyone,” said Avram. “Number input fields can help, but there are other ways to get to our desired outcomes, for example, by forcing a numeric keypad on a text input, adding descriptive field labels that indicate the requirements to enter a number, and form validation and errors that work seamlessly with screen readers and other assistive technologies.”
My best recommendation for trying to maintain as much as accessibility as possible is to use an online tool that will check your webpages for accessibility, such as the WAVE accessibility tool.
If there’s one takeaway here, it’s that it’s impossible to deliver the kinds of complex functionality many projects demand while simultaneously using the number input. It’s an either/or choice, and the way I see it, you’re better off ditching the number input.