The number input is the worst input
stackoverflow.blog
stackoverflow.blog
[0] https://kilianvalkhof.com/2022/css-html/are-you-sure-thats-a...
Good rule of thumb: if a reasonable person calls it a number, but your application is never going to perform arithmetic on it[0], it should probably just be a string.
[0]: Yes, a credit card number can be checksummed, but that's more in the sense of a CC# being a sequence of numbers rather than one int.
Sometimes you can get into secret menus if you play the tones for them...
I'm def. gonna try this out. I usually pres & and # a couple of times, because it often skips the useless menus and takes me to a person
Yes. Depending on your OS, it might even have the sound files:
https://pbxbook.com/other/dtmftone.html does. I'll try a company I know takes at least 40 minutes usually :
Also, something that annoys me about VOIP is that they don't take into account the different tones in different regions. Here in the Netherlands we use 425Hz fo dial tone etc. It always feels very emulated because it's a different tone.
It was mainly for doctor appointment reminders, though, so hopefully those called still had their appointments written down somewhere (or also signed up for email reminders).
The client really didn't want people sent to live agents if at all possible, as they only had a certain low number of agents and wanted to keep it that way, so we had extra prompts that tried to convince the user to give the app a try first before we did a transfer to an agent, but it was something that could start the process off.
And this was an IVR app for a Fortune 500 corporation, not a small company.
It surprised me coming from Apple Business Manager. It was unprofessional. Don’t skip the docs, guys!
Result: As expected, my problem wasn’t solved by following their 18-step DUNS/Apple process during the last 8 month. (My problem: My company changed both address and name, they still have both addresses with the old one as primary).
A faculty that was, of course, lacking at this particular organization
There's almost always a regular language more constrained and useful than .* that contains the entire set of acceptable terms (although sometimes it'll be a strict superset, in which case DFA acceptance cannot constitute complete validation).
A really small example of this is postal codes in Canada. For a long time the norm was to put a hyphen between the two clusters: A1B-2C3 but then at some point a lot of websites decided that's bad and they started rejecting it, often with really obtuse messages. This is just annoying and no one is really well served by it. Canada post doesn't care.
And that's not even getting into 0 vs O and the fact that yelling at the user for entering the wrong one is rarely helpful.
I think most of the time the better thing to do is attempt to normalize and ask the user if the normalization is correct. For a numeric thing like a phone number this is probably stripping out non-numbers (other than + at the start) and putting hyphens back in and validating the number of digits you get back, and presenting it to the user if it differs. More work but feels way less hostile to the user.
I really can't think of any case where changing a "0" to an "O" is a good idea (or vice versa), except like base 58 whre you're explicitly avoiding both.
Either way if you're going to normalize you need a regular language, so I think you're kinda missing the point here on what regular languages mean in this context?
The real point is that you want to have one regular form for the input in your database, but imposing that one that you prefer on your users creates friction when their experience of the world differs.
As for 0 vs. O, in a Canadian postal code it doesn't matter, because there is indeed a very regular language to them: letters alternated with numbers. A round circly thing in a numeric position is a 0 and a round circly thing in a letter position is an O. No matter what. The only time this actually indicates a problem is if the pattern ceases to hold after the round circly thing, in which case it may or may not be the 0/O confusion that's the problem but it was wrong anyways.
I'm not saying you should store it wrong, but if a user enters "HOH-OH0" and you ask "did you mean 'H0H 0H0'?"[1] and they say yes then you've given the user a much better and helpful flow than "Invalid Postal Code, please fill out the form again."
[1] This is a 'real' postal code btw and it goes to a weird santa-letter black hole even though it doesn't indicate a geographical location that corresponds to the north (an H prefix is for Montreal).
"one hundred seventeen" vs "one hundred and seventeen" are different, 117 vs 100.17
"twenty three eights" vs "twenty and three eighths" are 23/8 vs 20 3/8.
I don't know why this idea is upsetting to people.
https://www.grammar-monster.com/lessons/numbers_how_to_write...
I think people are forgetting, before the days of numeric calculation by machines, there were rooms full of people tasked with keeping track of these things.
back when we wrote checks, you didn't write the word "and" till you got to the cents (US) on a line that was preprinted "dollars": one hundred fifty three cents dollars" vs "one hundred fifty and three cents dollars".
It's history, it's interesting, it's not meant to throw you into a panic or fits of anger. And I very much doubt that you speak for all of English speaking countries, and through history as well, but must admit you might and I'm lucky to encounter an historian of numerical orthography.
(Update: unless the units were expressed after the following number, like 5 dollars and 13 cents, which still wouldn’t express a decimal point.)
it doesn't express a decimal point if you think of cents as a completely different unit of currency from dollars, but if you think of cents as 1/100ths it actually does indicate the decimal point. "5 dollars and 13 100ths" which is what cents means, and which is sometimes used when not referring to money, for example items that are measured in centiles such as interest rates. I think our forebears were more likely to throw words like centile around, and thats how they came up with the word cents.
My cousin is Italian and he always says "for cent" to me and I scratched my head till I realized, per is translated to for from Italian, and they say "25 per cento" so he's just translating it to English as it makes sense to him, not realizing we also have the word per.
and fwiw, I don't think it's a regional difference, I think it's a difference between certain traditions within the banking and accountancy areas, vs outside.
For more interesting currency matters, go back to https://en.wikipedia.org/wiki/£sd#Writing_conventions_and_pr..., where you had three items, and “£2/4/6” would typically be pronounced “two pound, four and six” (or sometimes “two pounds, four shillings and sixpence”). This shows more clearly that what it’s a perfectly normal “and” like any other in English. (Also that conventions can certainly allow elision in understood contexts. I’ve never heard of “one dollars and twenty-three” for “$1.23”, but it would be consistent with the sorts of shortenings that sometimes happen.)
I even found this article about how "and" doesn't actually mean decimal point: https://www.grammarphobia.com/blog/2012/02/decimal-point.htm...
I think it dates from the time when the only decimals the average person would use were in currency.
Your link is the only one I could find on the first page of google that states "and" means decimal point. Every other source I could find says "100.17" is either "one hundred point one seven" or "one hundred point seventeen".
This is an odd case, in that the house number is a "number": in the US it generally indicates distance from some fixed line, and the parity can indicate which side of the street it falls on. But then people will write them with As, Bs, Es, etc. attached.
That sounds like it would be a better job for a linter than for a compiler.
lambda calculus tells us, stick with strings even when you're doing math
This is fairly commonly used for multi-unit dwellings, especially when someone turns a "normal" house (with a purely numeric street address) into multiple units, including renting out their basement.
In subdivisions the houses are often consecutive numbers (with odd/even numbers on opposite sides of the road), and it's not like the city is going to re-number every other house on the street.
And that's why I have a home address that doubles as an input fuzzer.
I'm not sure how mail carrier software works, but in general there's a lot of variations of the same address that still lead to mail getting delivered correctly (and some addresses where the mail can't be delivered at all)
For U.S. apartments, usually any of these work "123A Some St" "123 Some St #A" "123 Some St Apt A" "123 Some St Unit A"
USPS has a canonical list of all valid addresses. In most cases of hand written letters, it comes down to a human’s judgement call.
I live in an apartment, let's say unit 555 at 123 Main St, and my canonical address has the form 555-123 Main St. This is not unusual in any way.
It is vanishingly rare to find a business, software, or customer service agent that is willing to enter this address correctly, even when dealing with my provincial government or my federal government. They always want to put "Apartment" or "Unit", or move the apartment number after the street, or some other transformation.
And my favourite case of interesting address numbers in the US, menomonee falls, which includes addresses such as "W162N7420 Tamarack Trail" [1]
0: https://www.mjt.me.uk/posts/falsehoods-programmers-believe-a...
I run into this sort of thing somewhat frequently. A multinational food delivery company here had a period for a couple years where it'd parse "1st whateverstreet 123" as an address on whateverstreer with the number "1st", dropping the 123 entirely. This may seem a bit silly but keep in mind that over here "123 Annex B" is a valid house number for instance, which might be a different building from "123B".
the developers obviously did not realize that social security numbers may start with a leading zero. (so can postal codes!)
The approach just seems to be asking for identity theft/fraud...
On the one hand a ssn number(or any identifying number) should not need to be any more secret than the name it is replacing, your ssn should be able to be publicly available.
However, this is the real world and many people and institutions use the ssn as the sole source of identity, which means it needs to be kept secret.
The SSN does not have the attributes of a good permanent identifier of a unique person. If you get an SSN with three consecutive 6's in it, you can get it changed to another one not containing that string. Worse yet, the Social Security Administration has reserved the right to reuse the SSN's of persons deceased (IDK if they can or might do that without giving further notice). Furthermore, the US government talks as if there are two completely different kinds of numbers that each use 9 digits, and that they might overlap, ie use the same numbers for different entities; one being SSN's and ITINS, and the other EINS. However, the practice of the IRS and SSA has been to do their best to make sure that they do not overlap, at which the results have been as good as can be expected, but not perfect.
As many games have been lost by one card too many as by one card too few.
Yes, there are ways to trick Excel into interpreting the value as a string. None of them are foolproof.
I will never sum up a list of phone numbers, nor will I ever divide my CC number by two.
They’re strings that just happen to be made up of numbers.
Credit card numbers are used with numerical operations
GP is right. You never do math with two credit card numbers as inputs. You can’t negate a credit card number, or find its absolute value, or square, etc.
It’s just a string of digits.
If the number already contains the check digit, drop that digit to form the "payload." The check digit is most often the last digit.
With the payload, start from the rightmost digit. Moving left, double the value of every second digit (including the rightmost digit).
Sum the digits of the resulting value in each position (using the original value where a digit did not get doubled in the previous step).
The check digit is calculated by 10 − ( s mod 10 ) {\displaystyle 10-(s\operatorname {mod} 10)} {\displaystyle 10-(s\operatorname {mod} 10)}.The issue is that many beginner (and some experienced) programmers treat what should be opaque strings as numbers and throw them into a 32/64-bit integer, or worse, a double precision float (in JavaScript). This can result in data corruption if not done carefully. Then, when something comes in to challenge the programmer's expectations, the program breaks. For example, ZIP/postal codes are 5 numeric digits in the US, but in CA, they're of the form "A1A 1A1" (notice the space and letters). JavaScript's `parseInt` will return NaN on a Canadian postal code. Another one is house numbers; They look numeric, but can have letters or even fractions(!) in them.
Does the number 21 "contain" the number 2? Not in a meaningful sense.
However, the string "21" definitely contains the substring "2".
The digits in a credit card number are meaningless. They have no relation to each other. If you choose two digits next to each other one doesn’t represent groups of 10x as much as the other digit. Or any other quantity.
The digits are effectively just symbols, not quantities like in a mathematical representation.
inputmode=numeric
Further, for credit cards, you can add `autocomplete="cc-number"` to the input and it will provide platform-specific UI for pre-filling the credit card number.
https://css-tricks.com/finger-friendly-numerical-inputs-with...
It is a terrible advice, you shouldn’t use <table> for styling, but if you are representing a tabular data, by all means use <table>. I’ve heard some developers (mostly back end devs that dabble in front end) say you’re not supposed to use tables, and I’ve seen div soups where there definitely should be tables. And I blame overuse of the rhetoric “don’t use <table>”.
By all means, if your taking in a numeric value, use <input type=number>. You get frontend validation, localization, context aware soft-keyboard, accessibility etc. all for free. Use it.
If however, you don’t have a numeric value (e.g. a value that is simply represented with digits) use something else. In general, if ordering values makes sense, then most likely <input type=number> is your best choice.
In the real world, however, the browsers apparently a) don't prevent users from entering incorrect values b) don't allow the developer to do anything about it programmatically, by preventing access to these incorrect values (always returning empty).
The author brings attention to this problem.
Now it's up to you as a developer to decide whether the benefits of using <input type=number> outweigh the costs, but the costs are real and you need to be aware of them.
If you want to deal with inconsistent (and possible eccentric) user input: Use input.valueAsNumber
If you want to distinguish between empty and invalid inputs: Use input.validity.valid or input.validity.badInput
If you want to programmatically deal with incorrect entries: Again use the constraint validation API.
Note that there's also an inputmode="decimal" option which does have a decimal-point on Android and iOS
Really the answer is just, "don't use number most of the time, use regular text with the appropriate inputmode". The inputmode abstraction is better than the type abstraction; it lets you specify what you really care about most of the time (mobile keyboards) without a bunch of extra constraints bundled in there
> I imagine that either doesn't fly with mobile keyboard hinting or screen readers trying to hint what a correct value is
The `pattern` attribute isn't used for anything except validation as far as I know; the mobile keyboard at least is entirely driven by `inputmode` and/or `type`
Getting into the weeds here though. The advantages/disadvantages of regex-based validation are beside the original point (and anyway I prefer doing validation in JS most of the time, for various reasons, but that's also out of scope)
As you should! :) Preferably by using a parser-generator library. Validation is basically just an error mode of parsing, and parsing things with regexes is not only unreadable, but also loses a lot of valuable information about the error.
if (Number.isNaN(input.valueAsNumber)) {
// If only this message could also by localized
input.setCustomValidity("Please type a number");
} else {
input.setCustomValidity("");
}
But double luckily, we don’t even need to do this as we also get this for free, and as a bonus the message is localized.With 1'000'000 percent certainty.
8.320.320,23
…
No. inputmode has no localization, or validation.
If your locale uses period as a decimal mark, but mine uses a comma, you can type "42.5" while I type "42,5" and they are both the same numbers (both evaluate to 42.5). You also get localized front end validation for free if you use type=number, but you’ll have to implement it your self with inputmode.
> Fractional numeric input keyboard containing the digits and decimal separator for the user's locale (typically . or ,)
https://developer.mozilla.org/en-US/docs/Web/HTML/Global_att...
As for validation- you can get reasonably far with the `pattern` attribute, but many apps do validation with JavaScript anyway.
The benefit of inputmode is specifically that's it's less opinionated- it lets you give instruction to the system keyboard (which is a feature you can't otherwise provide yourself), but leaves it to you to handle everything else as you see fit.
And this becomes an even bigger issue if you use pattern for validation (as you will have to sniff for the user’s locale conditionally adjust the pattern; good luck with that).
You also get this and validation error message localized with <input type=number>
EDIT: To clarify further. If I type 42,5 on my browser with an Icelandic locale, but your website uses inputmode=decimal, then my input will evaluate as NaN when you run `inputElement.valueAsNumber`. On the other hand you will get 42.5 if you properly set the type=number.
I also feel like you are underestimating the amount of localization that the browser actually does. Yes you still have to do some localization, but there is a whole issue that the browser does for you if you use the correct attributes. There are way more upsides which you might be unaware of.
Invariably, a designer/PM/someone will come back and say "Is there any way we can get rid of those stepper buttons on the right?" and then it gets changed to a text input with JS validation.
Also.. to this authors point, wouldn't you just use the 'validationMessage' if you're trying to extract the cause of the error from the field. I have yet to find myself in a position where I need the invalid value anyways.
Alternatively, of course, custom forms just make the buttons full-size, and I'm pretty sure they could be positioned next to each other: https://i.stack.imgur.com/IHqmt.png
The true fault here is ambiguous naming conventions that become booby traps.
Should we be blaming people for trying to pull open a door that has a pull handle even though there's technically "push" writing on it? It's just so convenient, as the door maintainer, to have just one type of door, though. Am I so out of touch? No, it's the users who are wrong!
Aside from redesigning a lot of things like this that could've been implemented better, we need to do better to avoid ambiguous naming. We should adopt more verbose naming standards. In this case, we could get rid of literal "number" to replace with "number-incremental," "number-money," "number-scientific" etc.
If people try to use just "number" and see it doesn't work, they should be able to quickly find the correct thing without having to decipher a made up nonsense name like "lambda" or scrolling through an alphabetical list of input types and having to spot every possible number type, read its description, and then compare every result to determine the actual correct one.
Yeah, developers can learn with time and it's good to know all the different options... But why aren't we setting people up for success in the first place?
Can't remember which app it was, and if it was a standard input from one of the dozen MS frameworks—but the testers on it must've been mightily incompetent. Imagining for a second that someone worked on that is like catching a glimpse into an abyss of pure stupidity. After this horror I'm quite relaxed about problems with inputs that at least allow me to type the damn number.
Your example probably stemmed from the case that the developer wanted the user to have instant feedback on validation, and instead of displaying some validation error message next to the input, they decided f-it - let's just immediately validate on input and not allow any invalid input. Bad/lazy decision, but I can see how it came to be.
If you focus the input field, hold the pointer over it and move the scroll wheel the value is rounded off, increased or decreased. There are 2 gotchas here.
Thus I found myself filling out a form that has to be filled out with the utmost accuracy. I look over the values again and again until the paranoia of potential financial disaster is sufficiently comforted. My eyes circle from field to field 6-10 times. (I'm never again going to make a mistake with this form ever again, enough is enough)
I then scroll to the submit button.
You can imagine what happens next, it involved a lot of adrenaline. One of the fields had changed, it was lower than before and everything behind the decimal point was unchanged. To make matters worse, I had no idea how this happened.
Next time I check all the values 20 times, scroll to the submit button and check the visible values again. So far so good?
I keep doing this and eventually it happens again!
It wasn't until the 5th time I finally deciphered what was going on.
<input type=integer>
<input type=float>
We need 2 different input keyboards on mobile: it should not be possible to type a dot if the input must be an integer.Currently seems to difficult to get a simple integer input: Chrome and Safari does not interpret step=1 as "no decimals".
Also: the up/down buttons should go. That should be an explicit option as they don't make sense in most cases. Might have a type=count for that.
<input type=currency currency=DKK>
so the keyboard input can clearly show the currency that is entered. This can be very important in multi-currency applications, e.g. travel (both customer and admin).Currency attribyte is ISO code: https://en.wikipedia.org/wiki/ISO_4217
Also: <input type=count>
which shows up/down arrows, and is a special case of <input type=integer>
There are other uses for fixed precision besides currency (co-ordinates, tolerances, etc.), but currency would be used a LOT!
> As a programmer, you might find this acceptable, but there’s a good chance your designer and/or product manager will not.
I couldn't care less if a designer is unhappy with the native functionality my browser exposes, it's called a user agent for a reason. They probably aren't happy with my custom style sheet either and this idea that designers' whims can override user preferences needs to stop.
It's really, quite a sad state of affairs.
Second a browser is less and less a user agent and more and more just an app runtime. It's only the lingering history that separates browsers from native app runtimes and not any real difference in expected semantics about experience control.
No but I expect them to realise the boundary of their own control.
> Second a browser is less and less a user agent and more and more just an app runtime. It's only the lingering history that separates browsers from native app runtimes and not any real difference in expected semantics about experience control.
This is only true if we let it be true.
I detest browser applications, which almost never are accessible, never use platform-native UI, do not integrate properly with system services. Except in dire circumstances, I simply refuse to use them.
I am in no way willing to give up my uniform platform to appease someone who things that every UI element should be "branded".
The choices here aren't branded vs unbranded, it's "does the website form submit validate user input or does it not validate user input?" Everyone wants the form to validate, and you can't reasonably validate input if you use that component, so no one can use the component.
People are probably used to providing input in a way to make the stupid computer happy, but that friction need not exist.
I felt sick reading that. We've all been there.
I spent an embarrassingly long time trying to track down some bizarre number parsing bug or obscure culture-specific behavior before realizing it was actually just users' cursors being over the number input while they tried to scroll, causing them to inadvertently change values just before submitting the form.
So something like "12.400,56" turns to 12400.56 and vice versa.
Also, is it just me or does this article seem to be a bit of an ad for "keenforms"? Its mentioned multiple times.
To your last point: I think it more or less obviously is an ad for keenforms, yes.
I ditched the number input.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
Phone inputs are especially painful to mask since you have to deal with a mind-boggling number of format variations.
> The built-in validation is visually inconsistent to whatever UX when you are building for your app.
To me, this is the kind of thinking that takes Web 2.0-isms too far and makes for actually really shitty UXes. (And yes, of course, I know that the responsibility for these peeves lies with product managers, designers and the like _as well as_ developers).
I do not need a picker to pick my state. I know what f---ing state I live in. I do not need to review a list of all states, hoping I'll know it when I see it. In fact, for a semi-structured and rather complicated piece of data like an address, why force the user to partial-parse it anyway? No, the fact that you can type the first letter does not help. Just let me type the abbreviation. I know what it is! I f-----g live here!
I know how to type a g-----n address, especially my own, and it's likely that, unlike you, I actually know how to do it correctly. You know, where my ward goes? Ward? You didn't think of that? My fractional street number or the fact that I don't have one?
I do not need a calendar widget to pick my birthdate, especially when the calendar invariably starts with today and does not offer a straightforward way to type the date in my local format. I know when I was f---ing born. I do not need to look at a calendar and think "Hm, I know it was a Wednesday... maybe some time in the '90s? Better click the tiniest f---ing left-guillemet « I've ever seen 360 f---ing times and then maybe one of those months will ring a bell!"
And also, run your braindead validation when I'm well finished entering my information. You do not need to red-highlight the field just because I put the point somewhere else outside of it. You do not need to give me a popup for every number in my phone number until there are ten digits. You do not need to confuse me by sometimes filling in phone number delimiters as I type, and sometimes prohibiting them from appearing at all. I've had two different phone number fields on the same form behave in both of these ways!
Thinking of form-filling-out as a "user experience" or "live interaction" is okay, I guess, but it can't dominate your thinking to the point that you lose why it's a "form" in the first place. There are lots of use cases that really are analogous to filling out a form, I think a lot of web sites could do a better job of keeping the power of that analogy and using dynamics to enhance it.
That aside, the presence of the decimal point raises four somewhat problematic questions: (1) how many decimal places are you going to allow on input? (2) how many decimal places will you display back to the user after they enter more decimal places than the typical user is expected to enter? (3) how many decimal places of the input will the application actually use in such cases? (4) How wide do you make the field to display the interest rate, and what do you do if the user enters something that won't fit there?
If you are writing software that should match the practices of more than one financial institution (bank, finance company, insurer, brokerage house, auditor, government regulator ...), the answers to those questions may be all over the map, and the number input widget probably will make it all an even bigger mess.
Highly specific types are very useful on screen-limited mobile devices as they allow software developers to implement very specific controls for them.
It ticks me off that now I have to lose my 10-digit input keyboard for these fields and have to use the tiny on-screen keyboard for everything.
Reading the article and the linked UK.gov article, it seems like there are two issues: (1) lack of more specific types leading software developers to (2) make bad decisions related to the number type for things that are numeric but not countable numbers.
How about we just add a few specific types, or a subtype mechanism.
Eg specific types for dates, PINs, and so forth.
We would also need to add either a non-countable number type or a subtype of the existing number type. Under the hood it could even just be implemented as a string limited to digit characters, and would be usable for zip codes, etc.
- not everywhere uses a decimal, some uses the comma and a decimal for thousands. Using a number input, these things are handled for you.
- this seems highly specific for a SPA and not server-side
- “e” is a valid part of a number, I don’t understand why you have issues with it.
There may be exceptions but I guarantee you in most cases the product manager doesn't want the letter e.
My app was built with Rails, and if you enter the value "3.9e3" which represents the number 3900, Ruby will simply use the number 3 and toss the rest of the value away. Do you really want to add special functionality on the back end to covert that value into the actual value? I surely would not.
Also plenty of people use javascript without it being a Single Page Application. Keenforms is not a SPA, we use React for certain pages, but I wanted to keep server side rendering. Using Javascript is not exclusive to SPAs.
So, Ruby’s number parsing is garbage I guess. Hopefully it at least does this properly for floats?
"3.9e3".to_f => 3900.0
Something happens when submitting web based params. I'd be curious to see what other back end languages and frameworks do.
"3.9e3".to_i => 3
and
Integer("3.9e3")
raises "invalid value for Integer()". Really, nothing to see here. Ruby just doesn't treat "3.9e3" as a valid string for an integer (which arguably is correct IMHO)
I’ve also been messing with forms for twenty-something years, and I’ve never run into these sorts of problems but I understand the problems you are facing, especially after googling these problems and their solution in regards to Rails. I’ve heard it’s a productive language, but when you have to solve such simple problems, maybe not?
Sorry, I don’t mean to bash on your chosen language which is probably how this is coming across. I’m genuinely intrigued by these stack overflow answers.
Ruby will parse "3.9e3" properly. However Ruby on Rails param parser tries to prevent bad data from entering the system. So the e gets sliced off. There are things that you can do to prevent data from being entered that way.
However like I mentioned in the article and commented on multiple times its not always my choice. And overwhelmingly the product managers and stake holders I interact with would prefer to not see numbers submitted in scientific notation form. There's no reason why you would want to submit your age like that. It's highly unlikely anyone would need a product quantity value in that format.
And maybe most importantly the people who pay tell me all the time they don't want it. Does that make sense?
I may be misunderstanding the gist of your comment, but surely the only "bugged out" behavior would be to try and call parseFloat on the value of the input directly without accounting for localization. Why should JavaScript's number representation affect whether or not I can enter numbers in the way I do everywhere else? The browser offers an API[1] for displaying numbers in a specific locale after all, though it's annoying that you either have to hack something together using Intl.DateTimeFormat.prototype.formatToParts or use a third party library in order to parse them.
[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
A proper number is 123.456,78 in large parts of Europe. If I can't put that into your number control when my browser locale is set to Dutch, your custom number input has failed as much at the broken input we're talking about.
It's not just the specific separators, of course; in India such a number is often written like 1,23,456.78 for example, grouping numbers entirely different. Don't assume everyone is American.
That's not my experience. I used a number input field for actual numbers (i.e. amounts of currency), but on some phones (specifically Samsung phones), it would show up with a full stop for decimal points (even though the locale was explicitly set to one with commas for decimal points), and users were unable to enter decimal numbers on Samsung phones.
Unfortunately, the handling of the number input field is extremely browser/OS dependent.
Eventually, I decided to go for text input, with numeric for inputmode, and simply interpret both "." and "," as decimal points (not permitting the user to use thousand separators, but few people would do that for input anyway). A bit awkward, but it worked.
Note: Using text and inputmode=numeric did not technically solve the issue of Samsung phones persistently showing the wrong keypad, but the JavaScript interpretation was the real solution to the problem.
Initially, I thought it was a problem with converting a React app to a native app with capacitor, but I tried the same Android app on a different (non-Samsung) Android phone and it did not have the problem (iOS similarly did not have the problem, both web and native version).
I think people would have fewer issues with it if the browser transparently converted it, either on entry or when calling .value. It's a somewhat obscure case that's easy to get wrong.
For example if I enter 104e4 into a number input with ID test, I get these results in Chrome/Edge:
> $("test").value
'104e4'
> parseInt($("test").value)
104
> parseFloat($("test").value)
1040000
> $("test").value - 0
1040000
Same with decimal points. It's a weird foot-gun because the solution is only half-there.
If you enter the value "3.9e3" which represents the number 3900, Rails param parser will simply use the number 3 and toss the rest of the value away. Do you really want to add special functionality on the back end to covert that value into the actual value? Most of us would not.
I'd be curious to see how other languages and frameworks handle this issue but the e for many of us is a real problem. Most people aren't even aware of it, and learn the hard way.
How would you expect users to enter numbers on the server?
That's a very programmer-centric take. A very, very programmer-centric take. The use of "e" for exponent in scientific notation is a very computer-oriented take on the problem. Such other places as you may have seen it used are leaks from the computer representation. Nobody else sees numbers that way; scientific notation is generally written as 3.278·10³⁶ (only with better superscripts), which is how it is taught in schools for the most part. There are many contexts where I would say it is not a valid part of a number, because I don't expect my users to know scientific notation, let alone an idiosyncratic rendering of it used only for historical reasons in certain niches of the programming world.
I guess the point is, you can parse it and output it in whatever format is appropriate, regardless of how it is stored.
If you are creating software for engineers, that's a fair assumption to make (that will understand what an exponent is). The public at large? Absolutely not.
A large segment of older adults have never used them.
A _scientific_ calculator? Because many cheap calculators will just overflow and not use the scientific notation.
You severely overestimate the... amount of data people retain from school (to put it in nice terms).
My (c) 1977 version of K&R C explains printf() around page 145, and it supports the %f notation for output of float's as 1.234e-8, etc.
This Fortran IV manual (early-mid 1960s, https://www.math-cs.gordon.edu/courses/cs323/FORTRAN/fortran...) lists the same exponential notation, but with capital E for REAL's and capital D for double's.
This pre-dates the first hand calculator I know of, the early HP's from 1968. These machines used the same notation as the HP-35 pictured below (https://www.hpmuseum.org/rpnvers.htm#num).
The HP-35 calculator came out in 1972. According to the page below, the scientific notation used is of the form
1.234-8
i.e., without the E (see the second row of the gallery).
https://vintagecalc.com/hp-35-red-dot/
Just a couple of data points.
It’s a pain in the arse to write, though, which is why quite a lot of scientists and engineers use e even though they don’t know anything about programming and are very, very far from being CS people.
I don’t know anyone who would enter 310^8 naturally in an input field (besides, using for multiplication itself comes from ancient technological limits, but nobody uses the proper multiplication sign either).
So yes, you need to support e for scientific notations in any input field that can be used for large or small numbers.
> scientific notation is generally written as 3.278·10³⁶ (only with better superscripts), which is how it is taught in schools for the most part.
That’s how we write it in LaTeX and our reports, articles, and such. And presentations if you’re lucky. But again, nobody writes that if presentation does not matter enough to go through the hassle. Certainly not in plain text where you’d have to use Unicode characters, at which Windows is completely incompetent.
As a Brit that looks really weird. I'd expect 3·278×10³⁶.
It's not even just digits, it can also start with +.
You mentioned inputmode="numeric" a few times as a possible solution. Does Keenforms make use of that?
As for min/max limits being bypassed and needing to do server-side validation also... well, yes? But, don't you have to do that even if you're using javascript for validation? The user could modify the DOM directly and replace the form control with one of their choosing that doesn't have javascript listeners, or submit a request from the javascript console, or even figure out all the required cookies and everything and submit a request with arbitrary params using `wget`. The server must always validate client input.
I built a form that gave a price estimate for a product, and it would change as you modified inputs on the screen. One of the requests was to treat a blank number input as a zero. That particular input was not required. The ideal situation would have been to default the number input to zero, but the product manager wanted to let the user leave it blank.
The problem became evident when the calculations to generate the price estimate treated a blank value and an invalid number value the same. You always get a blank string whether its blank or an invalid number value. To be honest I really hate whoever made this decision with the W3C committee or whoever it was. It makes zero sense that you let a user put it bad data but you won't give the invalid value via javascript. This was a deal breaker. We had to switch to the text input.
It should also be noted that the built in validation for the number input takes precedence over whatever javascript written to generate an error message. There were complaints from the designer about this issue. It may seem like a petty thing but again I don't get to make these decisions, they are made by the client.
Let's say each spare part is an extra $5, so if the user enters "1", that's +$5. and if they enter "4", that's +$20. If they enter "0" that's +$0.
And if the user enters "quux", that comes out as a blank value, so you treat it as "0" and modify the price by +$0.
Which is...fine? What extra price did you want to add to the calculation if the user requested "quux" spare parts? Does anything else even make sense?
If you need to tell the difference between an invalid value and a blank string, you should be able to use "checkValidity()".
Sure, being able to retrieve the literal invalid value might have been nice to have in some ways, but I can't figure out why not being able to get it is a blocker for using the "number" type at all - even with the requested design constraints.
I'm glad I learned something. And I'm really appreciative the way that you asked, it's been kind of nasty in the comments section.
However this not resolve the visual inconsistency issue for displaying error messages. Many complex forms have their own method of displaying error messages. It requires custom HTML and modifying the DOM. It rarely happens but once in a while the designer wants the invalid value mentioned in the error message. These are all issues that cannot be circumvented with the number input.
I don't love avoiding the number input - but I prefer to keep my job and my client happy. I don't have final say on these kinds of things. Accessibility matters to me, but keeping my job matters more. I've lost a lot of time fighting with the number input.
<input required type="text" inputmode="numeric" pattern="-?[0-9]+" title="Integers only" />
<input required type="text" inputmode="numeric" pattern="-?([0-9]+|[0-9]*\.[0-9]+)?" title="Decimal numbers only" />
<input required type="text" inputmode="numeric" pattern="[0-9]*(\.[0-9]+)?" title="Positive decimal numbers only" />The first bunch of times I could handwave it off as a result of Stackexchange having hundreds upon hundreds of sub-sites, but that doesn't work months into the deal. It's not like I'm on a mission to visit all those sites.
A QWERTY vkb in numbers / symbols mode have tiny number keys compared to a number pad.
If browsers validate differently, then fix them.
Which you would know if you read the article.
In my experience, performing a culture-specific decimal.TryParse() at form submission time is the most robust way to validate something like a wire transfer amount. You can also do regex replace javascript stuff, but there are always some dragons in that realm (especially as you cross borders). Your backend is almost always going to be a better place to parse and verify user input.
Regardless, I think the award for worst input goes to "datetime-local". The MDN page for it even says "Because of the limited browser support for datetime-local, and the variations in how the inputs work, it may currently still be best to use a framework or library to present these, or to use a custom input of your own". Followed by the date and time inputs, which are a real pain to work with.
I wish there were a web standard for modular, customizable, styleable inputs and pickers. It would eliminate a lot of needless wheel-reinventing and also make the web more accessible.
Yes, input type="number" is not the best, but when I ask for 2FA codes or credit card number a metric keyboard makes sense. And this is currently the best way I know to achieve it.
Indeed. All of the issues the author is experiencing can be easily fixed with simple and readily documented javascript methods:
> 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).
> Different browsers accept different characters
Use inputElement.valueAsNumber and stop worrying.
If you send the form unaltered (that is, without intercepting the submit event), use a custom validator.
https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputEl...
> Min/max limits can be bypassed
Use frontend validation, e.g. inputElement.validity
https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Cons...
There are plenty of weird form elements out there, but input type=number is actually one of the better one. But the author is definitely very right about one thing:
> You should only use the number input when dealing with mathematically relevant numeric values
Mathematically relevant might be to strict. I would say that if ordering the numbers makes sense, then input type=number most likely makes sense as well. If your data is simply represented by a number (e.g. zip codes; 90210 < 98112 is a weird statement) input type=number is the wrong choice.
The fact that the DOM API returns a blank value for an invalid number is a massive misstep on the part of whoever makes the decisions surrounding the DOM API. The W3C? Whatever, this is a truly awful decision.
I don't know pretend to be the expert. But I've seen a lot of things, and I've learned a lot over the past 15 years. For certain requirements there is no way to clear this problem.
const value = input.value ? input.valueAsNumber : 0;
Or if you want to be super defensive: const value = Number.isNaN(input.valueAsNumber) ? 0 : input.valueAsNumber;
The nice thing is that constraint validation will not validate empty inputs unless you put the required attribute on the input.However if it were me, I would default the input field to 0 (as in <input type=number value=0>) so that most users wouldn’t be confused by an unexpected default behavior.
On the other hand if the input is blank you want to treat the value as a zero and perform the calculation.
The problem of getting a blank string for an invalid value means you cannot make the distinction between the 2. I cannot make it any clearer than this.
Not everyone wants to treat a blank number input as a zero, and the ideal situation would have been to default the number input to zero. However like I said in the article multiple times it's not always my call or decision. That why the native validation and visual inconsistency across browsers as well as non compliance with mockups is a problem I've encountered multiple times. When you you cannot see an invalid value or make the distinction between blank and invalid number you lose control over work flow.
Also you rubbed me the wrong way with the snide "indeed" comment. Talking down to people is not a good way to generate a thoughtful debate. I try to approach these things with a certain level of humility. I don't know everything, I even learned a couple of things from other people when I published this article. Have you considered that maybe you don't know every possible requirement or request that I have?
let value = input.valueAsNumber;
if (Number.isNaN(value) && input.validity.valid) {
// or !input.validity.badInput if you want to be specific
value = 0;
}
If the field is empty you’ll get 0, if it is an invalid number you’ll get NaN, if it is a valid number, you’ll get that number parsed according to the user’s locale.The current implementation does allow for variety of use cases, it does allow for developers to distinguish between an empty and an invalid value. (it does not allow developers to distinguish between different valid representation, but I consider that a feature as it accommodates for different user eccentricity and locales; as long as you intercept the submit event and use input.valueAsNumber).
I’m sorry that I was insulting, but I’ve seen a lot of people on this forum with opinions about the state of front end development while not having any sort of expertise, and only rudimentary experience (as their expertise lies elsewhere). In your article you complain about front end feature that we front end developers use all the time (even you admit to using it), you complain that it is lacking, but you don’t even mention the techniques we use around those issues. There is no mention of input.valueAsNumber in your article, neither do you mention constraint validation API. Both are tools which allow us to deal with the issues you mention.
Elsewhere in the thread there are people recommending that you simply don’t use <input type=number>, this is a horrible advice (you your self admit there are use cases for it). But this is what happens when you misrepresent the techniques that front end developers use to deal with issues in the platform (or, worse, don’t mention them at all).
I'm going to read more about the constraint validation API.
I stand by my criticism of the fact that the DOM API does not give you the value that appears in the number input. It's actually infuriating.
Also your solution does not solve the problem of a stake holder or product manager or designer who is unhappy about the visual inconsistencies across different browsers and the different validations. Yes the built in validation is useful. However for many of the clients I work for they have high expectations and different demands. The solution you're providing might meet the technical requirement of treating blank like a zero but it would not be accepted by the clients I deal with.
The built in browser validation takes precedence over the javascript validation that is custom built. This has become a massive problem. Even with the ability to customize the error message that doesn't mean the people who are designing or paying for whatever I'm building will find it acceptable. I haven't tested it but I'd be curious what would happen with a large form and multiple native errors, and how do you direct the user to go to each of the inputs that have errors.
I'm not going to list every possible use case, but I've seen a lot. Once you cross a threshold of complexity with javascript form validation the native validation becomes a hinderance that is hard to overcome.
I know there are people on this forum with opinions without having the level of expertise that merits making comments. Not reading someone else's comment while being insulting doesn't help either.
And as far as I'm concerned avoiding using the number input is the least worst option for many of the projects I'm involved with. I could expound upon the input.valueAsNumber method in an update of the article, that's useful in a certain but not all cases. I stand by the content of the article and based on the clients I serve I plan to continue to avoid using the number input. The invalid value as blank string is a deal breaker.
What I do is I actually implement my custom validation with the constraint validation API (input.setCustomValidity()) and display the errors from there (using input.validationMessage). The custom validation actually takes president over other errors, if you don’t want that you can conditionally only set custom validity to a non-empty string when input.validity.valid === true.
There is one annoying part about this method, it is that invalid form will prevent the submit event from firing. This means that you have to put novalidate attribute on your form and fire the validation manually (using form.checkValidity() during the submit event; don’t use form.reportValidity() unless you want the browser to impose on your UI design). Now you can do whatever you want during the submit event, including: a) preventing it if the form is invalid, b) displaying error messages however you want by manipulating the DOM, and c) move the focus to whichever invalid input element you want.
I know this is involved, but it isn’t hard for a front end developer that knows what they are doing. The point is that a front end developer knows how to work with the platform (not against it) by using the same APIs as the platform does. In the case of <input type=number> that API is the constraint validation API. If you don’t use it, but still want custom behavior, you are going to have a bad time, and that is not the platform’s fault (and certainly not the fault of any one element in it).
If you are using a framework like React or Angular, which I do a lot, then you are using a different approach to validation. Typically you aren't using the DOM API, each framework has it's own approach. You can use the DOM but that is additional work and deviates from the tools provided by each of these frameworks. I probably should have stressed that much of my work is spent using these frameworks. The angular form API is hot garbage but again it's not my choice, I have to use what's been selected. I'm a big fan of React, I have not explored all the options available with React and accessing the value. Typically you aren't using checkValidity when you use React.
Rolling your own isn’t too hard either. In my job I rolled my own useValidation() for vue in less then 150 lines of TypeScript
If you need the actual invalid value for some reason (which is really rare IMO) you might have a point, but otherwise <input type=number> is a perfectly cromulent element.
On top of that the visual inconsistencies across browsers is a big issue. The native functionality of the number input will not be approved by most product managers and designers.
The visual inconsistencies have been figured out a long time ago. I don’t think it would be easy for you to find a competent front end developer that is unable to style a number input according to—or close to—your designer’s spec. I’ll admit that styling validation errors is a bit involved, but if you are using the constraint validation API (as you should) you are doing that anyway regardless of the input type.
const num = numInput.checkValidity() ? numInput.value : 0; // or some other default