Wednesday, May 2, 2012

Triggering Numeric Keyboards with HTML5

In the PhoneGap-powered mobile apps for EatDifferent, there's a part where you can enter measurements like weight and body fat — numbers like "12" or "150.5". I realized that I had to switch between the normal keyboard and numeric keyboard (the one with symbols and numbers) whenever I entered measurements, and I wanted to see if I could trigger the numeric keyboard by default for those input fields. HTML5 inputs support a few interesting new attributes, like type="number" and pattern="regex", and I figured I could use some combination of them to get what I wanted. So I started experimenting...

Using type="text" with pattern

The iOS developer docs actually include a section on how to trigger different keyboards and they recommend using type="text" with the specific pattern of either "[0-9]*" or "\d*" to trigger the numeric keypad, like so:

<input type="text" pattern="[0-9]*">

Unfortunately, when you start typing in that field on iOS, it will actually bring up the keypad that only has numbers, not the keypad which also includes symbols like the period, necessary for decimals. And on Android, you just get the normal keypad.

So then I tried setting that pattern to what I actually wanted to accept - numbers and periods:

<input type="text" pattern="\-?\d+(\.\d{0,})?">

On both iOS and Android, that just resulted in the regular old keypad showing up. No good!

Using type="number"

After deciding that Android doesn't pay attention to pattern at all and that iOS probably hard-coded the special case for the strict numeric patterns, I tried using input type="number" instead, with a step value of "0.01":

<input type="number" step="0.01">

Success! On both iOS and Android, a keypad with both numbers and a period shows up.

Now, I re-use my mobile web HTML for the website as well, so I needed to make sure that this solution would work well in desktop browsers. In older browsers, new HTML5 input types will just fallback to text, so we don't have to worry about them, but some newer browsers have special treatment for them, and that's what I needed to check. As I discovered, Chrome actually renders a spinner control inside the input for changing the number value by the specified step value. Maybe it's just because I'm not used to it, but I don't like that interface much, and it doesn't feel appropriate for my use case.

Fortunately, with a bit of Webkit-specific CSS, we can hide the spinner (kudos to StackOverflow for this):

input::-webkit-inner-spin-button {
    -webkit-appearance: none;
    margin: 0;


So, it's pretty cool that we can start being more semantic in HTML5 about what our inputs accept - and that browsers react to provide better input interfaces. But, it feels like it's still quite ill defined how browsers should react, and whether they will all react the same way, and whether their reactions will actually be appropriate for the variety of use cases out there.

Now that I've made this change to a more specific input type, I'll need to be on the lookout for browser changes to make sure it's always the best solution. It's not a change I'd make willy-nilly.

If you've done any experimenting with the new HTML5 input types and keyboard interfaces, I'd love to hear your thoughts in the comments.

No comments: