Posted on June 18, 2014 by Chris Harrington

Shim to customize output strings for date inputs on mobile browsers

I’ve recently been playing around with the HTML 5 date input controls. They’re pretty robust, especially in the mobile space, as all of the major mobile players have excellent support for most HTML 5 tags. One of the downsides that I’ve come across, however, is that the date controls don’t support the placeholder tag, or any custom display strings. So if I want to show a date in a particular format, I’m out of luck, as I have to stick with the standard “yyyy-MM-dd” format that most browsers natively display the date in. For the most part, that’s ok, but I spent some time coming up with a solution that provides both placeholder and custom date format support to the input date control.

A note here: each browser handles the date controls a little differently. Chrome on the desktop, for example, shows a bunch of different options for setting the date, including typing the numbers for each of the year, month and date fields, while also providing an arrow which opens up a date picker. Mobile browsers all open up the date picker while tapping on the input, which is great for this solution. However, this solution won’t work for desktop browsers, as the date picker doesn’t show until the user clicks on the little arrow, which is invisible.

The main idea is that, instead of using just a date input, I’m going to be using a second input as well, but this one will be disabled a text input. We’ll set the placeholder of this input so that the user sees a UI hint as to what the input is for. We’ll also wire it up so that the second input shows the correctly formatted date once the user has selected one via the date input. The key here is to position the date input relatively and float it on top of the text input while also setting its opacity to zero. The idea is that when the user sees the date, he or she is actually seeing the text input underneath. Tapping on the date opens up the date picker as normal. We’ll hook up to the change event for the date control, so when a user selects a date, we can set the text input value accordingly. Here’s the code.

First, the html. It’s pretty straightforward for this example.

The text input is disabled so as to disallow the user from entering text into it manually. Now the CSS.

#wrapper { float:left; width:400px; }
#label { float:left; width:100%; height:3em; }
#date { float:left; width:100%; position:relative; height:3em; margin-top:-3em; opacity:0; }

The interesting thing here is the #date rule. We set the width and height of the input to be the same as the label so that the overlap is complete. Then, we make it completely transparent by setting the opacity to zero. The margin-top value is the negative of the height of the label and input so that it sits on top of the label. Here’s the JavaScript. It makes use of jQuery because I’m a lazy kind of guy, but there’s nothing stopping you from accomplishing this in native JavaScript. It also uses Date.js, a date/time parsing/formatting library that I find extremely useful for manipulating dates.

$(function() {
    var label = $("#label");
    $("#date").on("change", function() {
        var rawDate = $(this);
        if (rawDate == "")
            label.val("");
        else {
            // Format the date however you want here.
            var formattedDate = Date.parseExact($(this).val(), "dd-MM-yyyy").toString("M/d/yyyy"); // 11/25/2014
            label.val(formattedDate);
        }
    });
});

First, we hook up the change event to the date input. This means that when the user selects a date, we’ll do some voodoo to set the label’s value. When the user selects a date, we grab the raw date value from the date control. If it’s the empty string (which happens when the user clears the date), we just set the label’s value to the empty string, which indicates that the placeholder text will be shown. If it’s not empty, we parse the incoming date value (which is always in the format “dd-MM-yyyy”) and then format it however we like, which, in this case is “M/d/yyyy”. Once formatted, we just set the label’s value and we’re done.

There’s a couple of caveats here. First, as noted above, this doesn’t work on most desktop browsers because of the requirement of making the whole date input transparent. Second, I ran into some issues on some “older” phones, like the Galaxy S3, whose native browser doesn’t register the change event on a date control. In that case, we can use the “input” event instead of the change event.

Overall, I’m a fan of this. It’d be nice of the date controls supported placeholders and custom formatted strings right out of the box, but until they do, this will have to do.

Thanks for reading!