7

The goal: To find a cross-platform solution for displaying numeric keyboards on mobile touch-based devices, with a minimum of hacks.

The problem:

I have a regular web application using data input forms, containing primarily numeric data. When a user interacts with my site on a mobile device, I would like to display a numeric virtual keypad as most standard keyboards require a second press to switch from alphas to numbers. I know that i can trigger different keyboard by setting the "type" attribute of input element:

type=number: This works great under iOS/Safari. I am unsure about other browsers on the platform.

On Android, this does not consistently raise the correct keyboard on various browsers and often results in unwanted elevator buttons on the input. I have yet to find a clean way to turn these off in CSS.

type=tel: This almost works on iOS/Safari, but the telephone keyboard lacks a decimal button.

Seems to work great across multiple android browsers, without any extraneous UI elements added to the page.

My current solution is hacky and simplistic. Based on a class that I'm already using for numeric validation, I replace each text element that should contain a number with a new input that is either a number or a tel type based on the detected OS/browser.

var isAndroid = navigator.userAgent.match(/android/i) ? true : false;
var isIOS = navigator.userAgent.match(/(ipod|ipad|iphone)/i) ? true : false;

if (isAndroid || isIOS) {
    var useNumberType = (isIOS ? true : false); //iOS uses type=number, everyone else uses type=tel
    jQuery("input.num").each(function () {
        var type = (useNumberType ? "number" : "tel");
        var html = this.outerHTML;
        html = html.replace(/(type=\"?)text(\"?)/, "$1" + type + "$2");
        this.outerHTML = html;
    });
}

I would prefer to not use browser detection and to not change out the inputs on the fly at run time. I could possibly introduce an http module on the server side that did basically the same thing, but that is not substantially better. I'm shocked that there isn't a CSS call for this.

Is there a better way to get a numeric keyboard with a decimal button, that works on all or most touch-based mobile devices without adding weird UI elements to the page?

-------------- update

I don't think there is a way to do what I really want to do, which is to setup a single input style or type that will work well across desktop browsers and all major mobile touch-based platforms. I settled on changing the type of the input through a direct DOM call rather through jQuery instead of rewriting the entire input via outerHTML. I suspect there isn't much difference in effect, but the code is a little cleaner. Since I'm not changing input types on the desktop, I shouldn't have to worry about IE's read only restriction on the attribute.

Ideally, I'd probably handle this on the server side so everything got sent to the browser in the format desired for the device making the request. But for now the new code looks more like this:

var isAndroid = navigator.userAgent.match(/android/i) || navigator.platform.match(/android/i) ? true : false;
var isIOS = navigator.userAgent.match(/(ipod|ipad|iphone)/i) ? true : false;

if (isAndroid || isIOS) {
    var useNumberType = (isIOS ? true : false); //iOS uses type=number, everyone else uses type=tel
    jQuery("input.num").each(function () {
        var type = (useNumberType ? "number" : "tel");
        if (this.type == "text") {
            this.type = type;
        }
    });
}
jatrim
  • 659
  • 6
  • 10
  • Does your page use a mobile framework? – Šime Vidas May 21 '12 at 21:43
  • Does it also have to work non-mobile? – nycynik May 21 '12 at 21:47
  • Ideally, yes, it should work on non-mobile browsers as well. Which is why i'm detecting the platform before making any changes to the page. I am not currently using a mobile framework. It's an adaptation of our regular site to improve performance for mobile browsers. In the future, when there's more money, we may be able to go back and write a mobile-only site. – jatrim May 21 '12 at 21:52

1 Answers1

2

Protip: when working with mobile, do NOT interfere with the user experience. This means keeping the built-in keypads as they are.

Some users may even have Javascript disabled on their mobile devices/browsers!

What you should do here is include an HTML hint to the browser. This way, mobile browsers should know what kind of content they are interacting with.

HTML5 includes several new <input> content types that should be supported on all modern mobile devices (and most modern browsers)

You can find the full list here.

What you want specifically is the following:

Old code:

Phone number: <input type="text" name="phone" />

New code:

Phone number: <input type="tel" name="phone" />

I don't know that any browsers currently support "tel", so you could use something like the following:

Phone number: <input type="number" name="phone" min="1000000000" max="9999999999" />

This is a bit of a hack, but is another option for you.

This is a MUCH simpler and more maintainable way of doing things, and better for the user.

Please let me know if you have any questions. I know this isn't directly answering the question, but it is a better way of doing things for now, in my opinion. :)

EDIT:

A possible way to get around this for each browser is by checking the user agent using JS/Jquery. I'm not sure exactly how to do this, but here is a tutorial on how to do so in .NET and changing the CSS for each element using JQuery.

EDIT EDIT!:

Try just modifying your code as such:

var isAndroid = navigator.userAgent.match(/android/i) ? true : false;
var isIOS = navigator.userAgent.match(/(ipod|ipad|iphone)/i) ? true : false;

if(isIOS)
    $(.phoneInput).attr("type", "tel");
if(isAndroid)
{
    $(.phoneInput).attr("type", "number");
    $(.phoneInput).attr("min", "1000000000");
    $(.phoneInput).attr("max", "9999999999");
}

I hope this out of everything works! You might have to switch the two if statements, depending on how your testing turns out.

Codeman
  • 11,457
  • 8
  • 48
  • 89
  • Thanks taking the time to respond. That's actually what the javascript above does. Unfortunately, I'm forced to make a device specific choice between `type=number` and `type=tel` because of rendering problems on iPhones vs. Android. I'm making the change on the fly rather than the html because it also has to render in desktop browsers without doing anything weird. I was hoping to get around one or both of those things, maybe by applying some magic CSS or input Attributes that I haven't been able to find. – jatrim May 21 '12 at 23:02
  • Perhaps you could use CSS? Take a look above in a moment. – Codeman May 21 '12 at 23:03
  • You're right about javacript, of course, but in this case, someone "more in charge" than me has decided we're not supporting a no javascript user in our application. Since a whole lot more would break than this, if javascript were disabled, it's not a relevant use case for this application. – jatrim May 21 '12 at 23:07
  • protip: read up on unobtrusive javascript. It's my current favorite design methodology, and it has enough business value for you to attempt to propose it in the future to your "more in charge" people :) – Codeman May 21 '12 at 23:13
  • Unfortunately, in most browsers, you cannot modify the type attribute of an input after it has been rendered to the page. That's why i'm re-rendering the entire input again using outerHTML, instead. Like you I would prefer a CSS solution, but i've been unable to locate any CSS that will affect the keypad selected. I'm considering setting everything to `type=number` and using CSS to hide the ugly elevator buttons. The CSS for hiding those buttons does not seem to be universal, though and it won't help browsers like Opera on Android where `type=number` is currently ignored. – jatrim May 21 '12 at 23:53
  • Are you using jQuery? The last thing I suggested should work great to change the elements after they've been rendered. That's the whole point of jQuery – Codeman May 21 '12 at 23:54
  • yes. I'm using jQuery. When I tried this I got very specific errors reporting that it was not possible to update the `type` attribute. That _may_ have just been Opera, but it broke the remainder of the script rendering. – jatrim May 21 '12 at 23:58
  • 1
    Yes, that might be the case. Take a gander: http://stackoverflow.com/questions/1544317/jquery-change-type-of-input-field – Codeman May 22 '12 at 00:03
  • Thanks for encouraging me to look further at modifying the type attribute. I hope that some day, all the browsers start handling all these html 5 tags the same way and introduce some better CSS for handling their UI. +credit for your effort. – jatrim May 24 '12 at 16:57
  • Thanks, hopefully you figure something out. : – Codeman May 24 '12 at 18:20