Number-only inputs aren't so straight-forward
Summary: While type="number" can come in handy, it's far from perfect, and in those cases where it lacks, inputmode="numeric" can come in handy.
If you’ve ever needed to create an input that should only be a number, I bet you’ve used input type="number"
.
This is good because it changes the keyboard on mobile devices to make things a bit easier… but it’s far from perfect.
First off, on desktop, you get these little up-and-down arrows.
<input type="number" />
I guess someone could use those to eventually get to their credit card number, but I wouldn’t really say they’re the best of user experiences.
And speaking of user experience, before we fix those up-and-down arrows, we can improve the mobile keyboards with an inputmode="numeric"
which gives us only numbers on iOS (Android already has a pretty paired down keyboard).
<input type="number" inputmode="numeric" />
Circling back to those up-and-down arrows we have two options:
We can remove them with some this CSS:
/* Chromium & Safari */
input[type="number"]::-webkit-inner-spin-button {
display: none;
}
/* Firefox */
input[type="number"] {
-moz-appearance: textfield;
}
Or we could switch our input back to an input type="text"
but keep the inputmode
on there, which keeps the keyboard numbers-only on mobile devices.
Then, we can add a pattern to that input so only numbers are considered valid.
<input type="text" pattern="[0-9]+" inputmode="numeric" />
You might be thinking that input type="number"
prevents users from entering other characters, but Chrome is the only browser to do that, so if you want to prevent that from happening, you’d need just as much JS in either case.
const numericInputs = document.querySelectorAll("[inputmode='numeric']");
numericInputs.forEach((input) => {
validateInput(input);
});
function validateInput(el) {
el.addEventListener("beforeinput", function (e) {
let beforeValue = input.value;
e.target.addEventListener(
"input",
function () {
if (input.validity.patternMismatch) {
input.value = beforeValue;
}
},
{ once: true }
);
});
}
Here is a working example with a few of these in place if you want to play around with them a little bit.
See the Pen inputmode numeric by Kevin (@kevinpowell) on CodePen.