javascriptandroidiosmobile-websitenumeric-keypad

Is there an acceptable cross-platform method for displaying a numeric keypad in standard web forms on a touch-based device?


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;
        }
    });
}

Solution

  • 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.