Mobile friendly Drupal form

20th Sep 2012

Let's go straight to the point, Drupal's default contact form simply doesn't play nice with small devices. Here I'll take about too major issues I had with it while testing it on my iPhone, the first a screen size problem and the second a functionality problem. I'll use CSS, HTML5 and jQuery to create workarounds that make the form mobile devices friendly without having to change Drupal's actual contact from.

The visual issue

Drupal's default text fields are sized at 60. That's about 1.5 times the width of the screen in portrait mode, the result is a bonus horizontal scroll bar! Defeating the purpose of removing the zoom and all! So in the mobile's media query view of my css it added this:

.contact-form {
    
    input.form-text {max-width: 300px;}
}

This will override the html size="60" attribute without the need to edit the actual contact from's core code which I just didn't wanna send the time to find away to edit in a template. And if i want to clear that on my css for bigger width media queries I can override it with this:

.contact-form {
    
    input.form-text {max-width: inherit;}
}

That solves the first issue, now onto the next.

The functional issue

This is about getting more semantically serious. The whole form uses

<input type="text">...</input>

Which is just fine for about everything but the email, especially when you're on a phone. Here's two iPhone keyboards:

iPhone standard text keyboard and email keyboard.

Fig1. - On the left the iPhone email type keyboard, on the right the regular text keyboard.

Obviously having the email keyboard display makes your life easier when punching in your email since you don't have to go to special characters to find the @ and you save some time. To tell the iPhone (and other devices with virtual keyboards) that they should use that email you can use the new html5 input types! Once again the problem is to change the element's html without having to edit Drupal's core or anything so this time I used jQuery by adding a block with my code to the contact form's page. The simple solution is:

jQuery("#edit-email").attr('type', 'email');

But to make life more interesting it didn't work because of some IE security issue and jQuery decided to block that feature all together. So here's a safe workaround:

jQuery(document).ready(function(){
  // Change email field type to be html5 correct
  // help with safari especially on the iphone!
  changeType('edit-mail', 'email');
});

function changeType(id, type) {
    var x = jQuery("#"+id);
    if(x.attr('type') == type)
        return x; //That was easy.
    try {
        return x.attr('type', type); //Stupid IE security will not allow this
    } catch(e) {
        //Try re-creating the element (yep... this sucks)
        //jQuery has no html() method for the element,
        //so we have to put into a div first
        var html = jQuery("<div>").append(x.clone()).html();
        var regex = /type=(\")?([^\"\s]+)(\")?/; //matches type=text or type="text"
        //If no match, we add the type attribute to the end; otherwise, we replace
        var tmp = jQuery(html.match(regex) == null ?
            html.replace(">", ' type="' + type + '">') :
            html.replace(regex, 'type="' + type + '"') );
        //Copy data from old element
        tmp.data('type', x.data('type') );
        var events = x.data('events');
        var cb = function(events) {
            return function() {
                //Bind all prior events
                for(i in events)
                {
                    var y = events[i];
                    for(j in y)
                        tmp.bind(i, y[j].handler);
                }
            }
        }(events);
        x.replaceWith(tmp);
        setTimeout(cb, 10); //Wait a bit to call function
        return tmp;
    }
}

Quite the lengthy fix, then of course there's always the unsafe alternative where you say who cares about IE let's bypass jQuery safeties. Something like that should work...

jQuery("#edit-email").get[0].type = 'email';

Anyhow the result is as follows:

Email field with the iPhone's email keyboard!

Fig2. - Contact form's email field with the email type detected and appropriate keyboard displayed.

Of course it would be simpler to just write it correctly in the first place but when using a framework or tool it might just not be practical so this offers an effective alternative to get the end result. Keep in mind that this is valid for more than just emails but also urls, dates, and etc. see links at the bottom for more info.

Links:

  1. Gist of the jQuery workaround above (forked of gminer's original solution)
  2. Read more on html5's new types
  3. Read more on iphone's keyboard