Date input in HTML5: Restricting dates, and a thought for working around limitations
You probably know that HTML5 introduced a date
input
type,
which constrains the value to a valid date string.
<input type="date">
largely eliminates the need for JavaScript-based
date pickers such as the one found in jQuery
UI. In browsers that
support the type, we can pick
a date using the browser's native widget. Below is an example of this
widget in Chrome.
Restricting input with min
and max
We can restrict date input in a few ways. The easiest is by using the
min
and max
attributes. Set the value to a valid date string using
the YYYY-MM-DD pattern defined in
RFC3339.
<input type="date" min="2013-10-01" max="2013-10-20">
In Chrome and iOS Safari, this will keep the user from selecting dates that are earlier than 1 October 2013 or later than 20 October 2013.
Using <datalist>
The datalist
element is
another way we can shape date input. Using datalist
presents the user
with a pre-selected list of dates, and the option to choose another, at
least in Chrome, Opera, and Safari for iOS.
We can even add a label attribute if, for example, we wanted to feature a list of holidays.
<input type="date" id="date" name="date" list="thesedates">
<datalist id="thesedates">
<option label="Groundhog Day">2014-02-02</option>
<option label="Valentine's Day">2014-02-14</option>
<option label="Flag Day">2014-06-14</option>
</datalist>
Can't eliminate days, but here's a suggested workaround
What we can't do yet, however, is eliminate classes of days from our
input. We can't, for example, prevent selection of weekends or disallow
Mondays purely through markup. Instead, we'll need to do a little more
work, using the HTML5 validation API, and the native JavaScript Date
object.
Let's take a look at some code that will display an error if the date selected is a Monday.
var date = document.querySelector('[type=date]');
function noMondays(e){
var day = new Date( e.target.value ).getUTCDay();
// Days in JS range from 0-6 where 0 is Sunday and 6 is Saturday
if( day == 1 ){
e.target.setCustomValidity('OH NOES! We hate Mondays! Please pick any day but Monday.');
} else {
e.target.setCustomValidity('');
}
}
date.addEventListener('input',noMondays);
When our form is submitted, our user will be notified that they haven't picked a date that we like. You should probably tell your user that X days are not permitted before they submit a date, of course. Just include some explanatory text near the field.
For weekends, you'll need to test whether
new Date( e.target.value ).getUTCDay();
equals 0 or 6, but the general
principle is the same.
Then we can use the :invalid
psuedo-class to
highlight that this form data is invalid.
Why not just stick to JavaScript-based date pickers, then?
Since the date
type has this limit, you may ask why we should use it
and not stick to existing widget scripts. The best answer I have is:
touch and scripting overhead. JavaScript-based date pickers are usually
prone to fat-finger input issues. Both iOS and Android (Google's
version, at least) have tap-optimized date input controls used by
browsers on those platforms. It's a bit more seamless for the user.
And by using a native type where possible, we eliminate the JavaScript code, CSS, and DOM operations that go with it. That's particularly important on smartphones where network capacity is more of a concern.