Years ago, when I first heard about the wonders of the upcoming HTML5 and in particular the new types of INPUT fields that browsers would have supported, well, I was jumping for joy. Thankfully, I thought, I don’t have to worry any more about checking dates, parsing text into numbers, using regular expressions and the like. Speaking of dates, I couldn’t believe that by simply changing the type attribute of the INPUT element to “date”, it would have saved me the burden of attaching some JavaScript plugin for a calendar-like user experience.
Those were the promises of HTML5. The reality of actual browsers is a bit different. Most browsers, with the notable exception of Internet Explorer, recognize the “date” input type and provide a built-in popup date-picker component. In particular, nearly all mobile browsers do that, thereby giving users the same date-picking experience they would have with native apps. Overall, the HTML5 input fields work well with mobile device browsers, but much less well with desktop browsers.
Apart from the complete lack of support for the ‘date’ input type in Internet Explorer, a browser that a significant proportion of users still chooses, the main problem with date input fields is that each browser has its own user interface. An interesting debate opens up here. Should you ignore all browser-specific differences and go with the fact that if users opt for ‘browser X’ they just like the date input experience that goes with it? Or should you put in some effort to provide a uniform date-picking experience regardless of what each browser may be doing with the date input type? Even when you opt for the second option you don’t want to lose the native date picking capabilities on mobile browsers.
In this article, I’ll look at all possible implementation choices (that I’m aware of) and try to work out a solution for HTML date picking that provides an ideal (or just easy enough) experience to users regardless of the device being used.
First Stop Is Modernizr
I’ve never been a huge fan of Modernizr but this is just one of those particular scenarios where Modernizr just fits in nicely and sweetly. Modernizr allows you to check whether the present browser is known to support the HTML5 date input field. Here’s the standard Modernizr code snippet you need to include in any HTML view with a date input field.
1 2 3 4 5 6 7 |
<script type="text/javascript"> $(function () { if (!Modernizr.inputtypes.date) { // Alternative date picking logic } }); </script> |
The body of the IF statement is left to you. Ideally, you would attach to the date input field any JavaScript plugin you like to use for comfortable date picking. You would use something along the lines of the code below, where datepicker() is one of the hundreds jQuery date picker plugins out there.
1 |
$("#day").datepicker(); |
This approach works nicely because it wouldn’t change the native behavior of the browser in any way, but at the same time it allows you to give users a better experience when they use a rather obsolete browser or a browser, such as Internet Explorer 11 or older, that just doesn’t support all HTML5 input fields.
The downside of using Modernizr in the way I’ve shown it here is that the same user that visits the web site using different browsers will have to take slightly different actions every time to enter a date. Frankly, it’s hard to objectively say whether this is really a usability problem or not. I believe it depends on the application and the expected range of users.
The “One Experience” Approach
A different approach consists in choosing one particular JavaScript date picker plugin and attaching it to whatever input field is expected to capture a date. In doing so, you don’t even use the HTML5-specific “date” input field, but fall back to the old-fashioned “text” type. In this way, all browsers will present an empty text box and the dynamically added plugin will do the job of picking a date.
1 2 3 4 5 |
<script type="text/javascript"> $(function () { $("input[data-acceptdate]").datepicker(); }); </script> |
The preceding code will likely go in a layout page or master page depending on the flavor of ASP.NET you’re using. In other words, it’s a global setting you apply once for the largest possible number of pages and views. In the code snippet, I assume you use the custom data- acceptdate attribute to mark an otherwise regular text input field in a custom date input field. The name of the attribute is arbitrary. In alternative to a global configuration, you can apply the setting individually to each input field by ID or any other selector.
1 |
<input type="text" id="day" id="day" data-acceptdate="yes" /> |
Let’s see pros and cons of this approach.
First off, the user experience is guaranteed to be unique and uniform across all devices and browsers. Is this good or bad news? For desktop browsers, it is definitely good news because users will deal with the same interface regardless of they come through Internet Explorer, Chrome, Safari or Firefox. It’s a different story for visitors using a mobile device. Users of mobile devices use the finger instead of the mouse to make a selection and might not have a screen large enough (and I’d even say the attitude) to accommodate popup windows like a calendar. This is especially true for smartphone users.
Tablets and even mini-tablets (say, a mini iPad) are probably large enough to allow a decent experience with fingers and popup windows. However, depending on the layout of the individual page, you may run into problems as users rotate the screen and pass from landscape to portrait and back. Clearly, fixing the layout so that users can comfortably select a date from a mini-pad in portrait mode is definitely possible but it’s a cost and requires a lot of usability tests. It’s exactly the kind of thing that drives managers crazy because they don’t understand why you have to spend billable hours (not to say days) on the “same” and “plain simple” feature-picking a date.
Overall, I tend to consider the “One Experience” approach good enough for desktop browsers but rather detrimental for mobile browsers. Swarms of usability experts have dedicated years of research to identify the ideal way to pick time and date on mobile operating systems. This means that there is a good chance that those native pickers are still easier to use than a JavaScript HTML plugin. In other words, I’m afraid you wouldn’t be serving users the best way by unifying the date picking experience on desktop and mobile browsers.
How can you serve different HTML markup on each family of device? In this context, the WURFL framework is quite helpful as it gives a quick and effective way to reliably detect the form factor of the requesting device. As you may learn from the http://www.scientiamobile.com web site, the WURFL framework has many aspects, each of which can be used to distinguish programmatically between desktop and mobile browsers.
If your goal is to minimize the use of the bandwidth and serve just the HTML that meets the purpose, you can use the WURFL OnSite library, namely an ASP.NET class library that parses the user agent and returns detailed information about the device and the browser. The OnSite library has a certain cost of ownership in the sense that hosting the library and downloading the latest device database on a regular basis is up to you. The same library is also available as a cloud service where you pay only for the calls you make and the information you retrieve. The WURFL InFuze tool, instead, will do the same job at the web server level. The net effect for your code is getting additional HTTP headers per request with device and browser information.
Finally, you have the client-side option, the easiest to try out and even free to use in production. The following line will inject, into the DOM of the page, a server-side calculated JavaScript object that contains minimal information about the requesting device.
1 |
<script type="text/javascript" src="//wurfl.io/wurfl.js"></script> |
The information is a plain JavaScript object with the following layout:
1 2 3 4 5 |
{ "is_mobile": false, "complete_device_name": Microsoft Internet Explorer, "form_factor": Desktop } |
The is_mobile property always returns true except when the device is a desktop browser. The form_factor property can take the following values: desktop, smartphone, tablet, app (when the page is viewed from a native WebView component), feature phone and a few more. Check out the full documentation at http://web.wurfl.io.
Using these pieces of information, you can programmatically change the type attribute of date input fields and attach any date picker JavaScript plugin you wish to use. Imagine you have the following markup:
1 |
<input type="text" id="day" id="day"> |
Upon loading of the page the following script will fully configure the input date field
1 2 3 4 5 6 7 8 |
<script> if (WURFL.form_factor == "Smartphone" || WURFL.form_factor == "Feature Phone") { $("#day").attr("type", "date"); } else { $("#day").datepicker(); // Whatever date picker plugin you use } </script> |
In this way, the native date picking infrastructure is preserved on mobile devices (just cell phones) and unified on desktops (and tablets) by using a jQuery plugin of choice.
Avoiding Date-Pickers Completely
Using popup date pickers is quite a common way of selecting dates on most computers and devices, but it’s not certainly the only way. For screens where users are expected to type in data quickly, I bet that a masked input field might be more appropriate. Even on mobile devices, bringing up the nice scrollbars to choose months and days is cool and effective but not especially fast.
1 |
<input type="number" id="date" id="date"> |
On a mobile browser, the above line of markup will automatically configure the keyboard in numeric mode for you to enter the date as a sequence of digits, for example in a “ddmmyy” format. That’s pretty quick to do and only requires some ad hoc parser either in the submit code of the hosting form or in the ASP.NET binding layer. It’s a bit of extra work, but it’s just the extra work you sometimes need to do in the name of usability and improved user experience.
If it is an acceptable decision to require users to type a date, here’s how you can code it for both desktop and mobile browsers. First and foremost, you might want to use a masked input field. There are many jQuery plugins for that and getting one that works for you is no big deal. My favorite is jQuery.MaskedInput and you can download it from http://plugins.jquery.com/maskedinput.
Adapting a masked input to work on dates is trivial until you need to set the date format based on the current locale. Here’s some code I ended up writing for this purpose.
1 2 3 4 5 |
var cultureDateFormat = Thread.CurrentThread.CurrentUICulture.DateTimeFormat.ShortDatePattern; var mask = cultureDateFormat.ToLower() .Replace("d", "d9") .Replace("m", "m9") .Replace("yyyy", "2099"); |
You can place this code at the top of any Razor views where you enter masked dates or you can incorporate the same values as plain strings in the view model class.
The cultureDateFormat programmatically reads the current short date format based on the thread locale. The short format for the English culture should be something like M/d/yyyy. The mask variable turns the system’s short date pattern into the text you want to see in the mask. In the example, it’s something like d9/m9/2099. As you can guess, the format of the mask depends on the syntax the plugin can recognize. In particular, the sample plugin uses the “9” to denote a digit but has no built-in support for the specific input logic of dates. In other words, 99/99/9999 is not an ideal choice to accept a date. The plugin can be added custom mask definitions, though.
1 2 |
$.mask.definitions['m'] = '[01]'; $.mask.definitions['d'] = '[0-3]'; |
The “m” now identifies either 0 or 1 and is perfect for the first digit of months. The “d” ranges from 0 to 3 and is acceptable for the first digit of days. Hence, “d9/m9/2099” is not perfect but it’s much closer to accepting a valid date than anything else. Here’s how you attach the mask to the input field.
1 |
$("#day").mask("@mask"); |
Another problem you face when using masked fields for dates is setting default dates in the input buffer. The problem is that whatever string you provide as default date must match the format of the mask. Here’s the code you may use if you have two date input fields for a from/to range.
1 2 3 |
var maskedFormat = cultureDateFormat.Replace("d", "dd").Replace("M", "MM"); var valueFrom = Model.From.HasValue ? Model.From.Value.ToString(maskedFormat) :""; var valueTo = Model.To.HasValue ? Model.To.Value.ToString(maskedFormat) : ""; |
Variables valueFrom and valueTo are now valid strings to initialize the masked input.
Summary
The task of creating a browser form that allows users to enter a date might seem easy before you need to do it. HTML5 rightly introduced ad hoc input types for the purpose but even now, a few years later, browsers are not completely up to the task. As you can see at http://caniuse.com/#feat=forms the area of browsers’ coverage of HTML5 form features is mostly green but for the most part it is only partial support. For dates, in particular, the support is lacking in all versions of Internet Explorer but it is available in Edge and most recent versions of all other browsers. However, beyond the support offered by browsers, it clearly requires more attention and care about usability than expected, if you need to provide a uniform experience for date entry
Load comments