The input types nobody uses
What you get for changing one word, the type that's a trap, and the element nobody uses at all.
Every form I audit has the same two mistakes.
There’s a date field with a JavaScript picker on it, several tens of kilobytes, with a calendar the designer specified, which on a phone replaces the excellent native date picker with a fiddly grid of small targets.
And there’s a phone number field that’s type="text", which on a phone brings up a full alphabetic keyboard for a value that is 10 digits.
Both are one word. Here’s the rest of the list.
What one word buys you
type="tel". A numeric keypad on mobile, with the large well-spaced keys people already use for dialing. No numeric validation, which is correct, because a phone number is not a number: it can have spaces, brackets, a plus, and a leading zero that matters enormously.
type="email" and type="url". Keyboards with @ and / and .com on them, plus format checking. Covered these in 2019 and they’re still the two most obviously worth doing.
type="search". A clear button in some browsers, a keyboard whose action key says Search rather than Return, and correct semantics for the thing it is.
type="range". A slider that’s keyboard operable out of the box, with arrow keys, Home and End, all working, announced properly, and which every custom slider component I have ever tested gets at least partly wrong.
type="file" with accept and capture. On a phone, capture opens the camera directly, which for a “photograph your meter reading” flow is the difference between two taps and eight.
type="color". A native color picker, for free, on a form nobody was going to budget a color picker for.
Each of these is a case where somebody shipped forty kilobytes to replace a native control that was better on the device most of their visitors use.
type="number" is the trap
The one that looks obviously right and mostly isn’t.
It’s for quantities. Things you’d add up: how many, how much, a price, a measurement. For those it’s fine and the spinner makes sense.
It is wrong for anything that is a string of digits rather than an amount. Zip codes, card numbers, phone numbers, one-time codes, account numbers, house numbers, anything with a meaningful leading zero. And it has two specific behaviors that cause real bugs: the scroll wheel changes the value when the field has focus, so somebody scrolling past a form silently edits it, and browsers differ in what they do with non-numeric characters typed into it, sometimes discarding them and reporting an empty value.
<!-- not this -->
<input type="number" name="zip">
<!-- this: numeric keyboard, no spinner, no scroll-wheel editing,
leading zeros preserved, and it's a string all the way through -->
<input type="text" inputmode="numeric" pattern="[0-9 ]*" name="zip"
autocomplete="postal-code">
inputmode gets you the keyboard, which is the only thing you actually wanted from type="number" in these cases.
The date family, and the honest caveats
date, time, datetime-local, month and week. Native pickers, and three properties that are hard to get any other way.
The displayed format follows the user’s locale, so somebody in a place that writes the day first sees the day first, without you doing anything or getting it wrong.
The value your server receives is always ISO format regardless of what was displayed, which removes an entire class of parsing bug.
And on mobile they’re excellent. The native date picker on a phone is a large, familiar, well-tested control, and it is better than every JavaScript calendar I have ever seen on a small screen, by a distance.
The caveats, honestly: you cannot restyle them much. The picker chrome is the browser’s and each browser’s is different, so your form will look slightly different in each, and there’s no way around that. min, max and step work; a “disable these specific dates” requirement doesn’t, and that’s a genuine reason to reach for a component.
<datalist>, which nobody uses at all
The most under-used thing in HTML, I’d say.
<label for="branch">Nearest branch</label>
<input id="branch" name="branch" list="branches" autocomplete="off">
<datalist id="branches">
<option value="San Diego">
<option value="Los Angeles">
<option value="Sacramento">
</datalist>
That’s an autocomplete. It filters as you type, it’s keyboard navigable, it’s announced correctly, and it costs nothing. The combobox pattern that people build with a library and get wrong, in six lines of markup.
Its limits are real and worth knowing: you can’t style the dropdown at all, and it suggests rather than restricts, so somebody can type something that isn’t in the list. For “which of our 11 branches” that second part is a bug and you’d validate server-side anyway. For “what’s your job title,” it’s the feature.
Why we avoid them, which is a real reason
I don’t think anybody skips these out of ignorance, mostly. They skip them because they can’t be styled, and a form where every field matches the design system except the date, which looks like the browser, reads as unfinished.
That’s a legitimate constraint and I’m not going to pretend it away. What I’d challenge is the conclusion.
Because the trade isn’t “custom picker versus native picker.” It’s “custom picker, plus its focus handling, plus its keyboard support, plus its announcements, plus 40 KB, plus the fact that it’s worse on the device most of your visitors are using” versus “a control that looks slightly different in Firefox.”
And if the desktop appearance genuinely matters to somebody, the native controls are at their best on mobile and at their most visually inconsistent on desktop, so there’s a version of this where the custom widget is a large-viewport enhancement over a native base. I’ve done that twice and it was less work than the full custom version and better on phones.
Four seconds, nobody notices
The form I reviewed lost the date picker on mobile, kept it on desktop because the client wanted the calendar, and the phone field became type="tel".
That second change took four seconds and is, I’d guess, worth more to their customers than anything else on the ticket. Nobody will ever notice it, which is the usual arrangement for this sort of thing 🙃