Maybe You Don’t Need a Date Picker
Calendar controls, date pickers, date widgets, whatever you call them, however they are described, they follow the same basic principle — present the user with a calendar to enter a date (and sometimes a time).
The native implementations come from browsers when authors use
<input type="date">. Usually a calendar grid, but sometimes built to look like a broken slot-machine or configurable date rubber stamp that your accountant uses.
Frameworks and libraries offer their own take on date pickers, with many more options from third-party developers. These appeal to developers who want control over the visual style, and sometimes function, of the date picker. Particularly developers who want to avoid a different experience across browsers.
The problem is that nearly every implementation of a date picker is a barrier for some set of users. I can comfortably say every one that I have seen is a problem, though perhaps there is a wonderfully robust one somewhere. Even the ARIA Authoring Practices, which is more comfortable with imperfect patterns, has not deigned to create a date picker.
I have been testing with users for about 20 years (so far). Something I see over and over again is the frustration with date fields that are anything other than a plain text field for well known dates (like birthdays). They can anger users. Enough that I have seen users quit a test (more than once).
Users do not want to have to stop their flow and learn this new user interface. They don’t want to experiment to see what keys work, or read a pile of instructions. They want to enter a date and move on. This applies just as much to native date pickers. They may only use their phone or computer to email and surf the web, not enter extensive date-specific information on a regular basis.
A developer may use a date picker a few times a day. Every few minutes when building a screen with a date picker. Heck, maybe only once or twice a week. But a developer may have used date pickers in one month far more times than an average user in a year or a lifetime.
I have not touched on the accessibility issues with date pickers. The ones that claim to be accessible aren’t.
For example, we know
<input type="date"> is a problem for voice users across browsers. Graham Armfield already produced a thorough report on the accessibility of the native control and came to conclusion that nope, it is not accessible.
I am constantly tossed date pickers from libraries and asked to evaluate them, and they are typically an accessibility quagmire. There is a reason most accessibility professionals tense up at the mention of date pickers.
Unnecessary detail about one library’s date picker…
- The buttons at the top of the grid to navigate to the previous or next month have no accessible name. If a screen reader user gives them focus, they will be announced only as “Button”. This is a WCAG 4.1.2 violation.
- The arrows in the buttons have insufficient contrast with the background, meaning users in sunlight, with poor monitors, or with low vision may have trouble seeing them. This is a WCAG 1.4.11 violation.
<select>menus for the month and year have no accessible name (via
aria-label, or otherwise). A screen reader user will hear the current value, but no label. While the value may provide context for the field, it does not provide context in the overall control. This is a WCAG 1.3.1 and 3.3.2 violation.
- The site provides a stack of keyboard shortcuts that the calendar control supports. While supported, nowhere is that support conveyed to users. Keyboard-only and screen reader users are provided no instructions on how to use the control, meaning they will likely arrow their way through months and years to find their choice. This is a WCAG 3.3.2 violation.
- The previous / next month buttons, the month select and the year select cannot be accessed by a keyboard-only user. Using the arrow keys does not put focus on those controls. Using Tab moves the focus to the next field of the form. Of the listed supported keyboard shortcuts, even if a keyboard-only user knew about them, there is no way to get to those visible controls, meaning they will likely arrow their way through months and years to find their choice. This is a WCAG 2.1.1 violation.
- The dates have an
aria-labelwith them that overrides the visible text and adds complexity to the term. While
aria-labeltypically will not work on a
rolemakes it work. In this case, instead of a screen reader user hearing “18” they hear “day dash 18”. A better approach would be to exclude the
aria-labelaltogether. This is not a technical WCAG violation, but is considered a usability issue for screen reader users.
- The currently selected date is not conveyed to screen reader users. It is only conveyed visually. This is a case where
aria-labelmay be useful to convey the state of the calendar date, perhaps as
aria-label="18 selected". It is possible
aria-currentcan work here. As it is, this is WCAG 1.4.1 and 4.1.2 violation.
- The week days are not conveyed to screen reader users for individual days. Because the calendar does not use a
<th>elements for each weekday, and because arrowing right or left moves the user regardless of the start or end of a row, a screen reader user will not know if a particular date falls on a Monday, Tuesday, etc. It does not help this is also mis-cast with
role="listbox". This is a WCAG 1.3.1 violation.
Round-up of WCAG violations in this calendar control as listed above:
- 1.3.1: Info and Relationships (A)
- 1.4.1: Use of Color (A)
- 1.4.11: Non-text Contrast (AA)
- 2.1.1: Keyboard (A)
- 3.3.2: Labels or Instructions (A)
- 4.1.2: Name, Role, Value (A)
Using third-party or native calendar controls can make a developer feel that the validation is handled. Handled by the collective intelligence of everyone who worked on the control.
But the developer still has to provide validation outside of the control. Sometimes validation is needed to support the fallback state for older browsers. Sometimes it is there to honor progressive enhancement. But mostly there should be server-side validation because we know scripts break and resources don’t load and data can be bypass client-side validation.
I cannot imagine that developers are going to let user-submitted content directly into their data structures without scrubbing it in some minimal way. And not just because of the fear of Little Bobby Tables paying their site a visit. As a skilled user, I can get around confounding controls by injecting the values I want using the browser’s dev tools, and developers typically account for data coming through outside of the carefully crafted client-side validation.
The point is, robust web sites and applications already do validation on the data outside of that provided by the control.
An Alternative to Date Pickers
Users generally do not want a complex date picker every time you ask for any date. At least not users with a keyboard.
Previously I have relied on plain text inputs as date fields with custom validation for the site, typically using the same logic on the client and the server. For known dates — birthdays, holidays, anniversaries, etc — it has tested well.
Text Field with Messaging
In this prototype I am still using a text input for the first field, but I also use client-side script to convert the data to a human-readable date that I present to the user. This way a user can get immediate feedback and worry a bit less about matching a specific arcane data format the developers prefer.
In short, I am trying to deliver far less code (and confusion) to the end user while accepting a broader range of date formats. I am letting the robustness principle drive my approach.
You will note that I ask for a U.S. date format. The weirdest one. This can be adjusted, of course, but I chose it to demonstrate how a globally confusing format benefits from immediate feedback.
The script to convert the date is the minimal amount of code to demonstrate the effect. It is not production-ready. It is not even good. Try it by entering “7 5 19”. Ideally, the date your script generates is the one you submit with the form.
Note the ARIA attributes, the connections between the fields, and use of
<output> to hold the message. These are all there to make sure it is useful for screen reader users and voice users.
<label for="BDay01" id="BDay01Label">Birth date <span>(MM/DD/YYYY)</span>:</label> <input type="text" id="BDay01" aria-labelledby="BDay01Label BDay01error" aria-describedby="BDay01confirm" onblur="valiDate(this.id,'BDay01confirm','BDay01error');"> <output class="confirm" id="BDay01confirm" aria-live="assertive" for="BDay01" form="Form"></output> <div class="error" id="BDay01error"></div>
Update: 10 July 2019
For more on
<output>, read Scott O’Hara’s post
<output>: HTML’s native live region element.
Dragon Dictate users are generally frustrated with all calendar controls, including the native ones we get from
type="date". In an informal test, this one proved usable.
Informal tests (anecdata) from other users showed this approach was no worse than a text field and far easier than a calendar control.
Places This Will Not Work
There are plenty of situations where a plain text field (with or without the messaging feature I prototyped) will not work.
If you need to see chosen dates, unavailable dates, weekends, holidays, date spans, date ranges, dates where counts from start or end dates matter, and so on.
What we know is that native and custom calendar controls are often a problem for users and applied where they are not needed. Before dropping the code on a screen as a matter of habit, consider if it genuinely helps the user or just your workflow.
I do not propose a perfect solution for the narrow use case I identified, but I am hoping it spurs rethinking the casual application of a more complex pattern than is often warranted.
What do you think about having a solution like this, plus a button next to it that launches a date picker for those that want it?
I think that is fine. Forcing the date picker is not, but letting users choose gives them flexibility. For one-off cases, you may want to let them know in the instructions as some users will not be aware there is an option until after they fill out the date field.
Love the idea of being able to enter a date in any way you choose, and letting the browser decode it, and return a date (eg. 1 January 2019) as confirmation.
It would be a great opportunity for browsers to take up the slack there too, updating
type="date"with regional variations etc.
But maybe, like James says above, having a calendar button as an additional option.
What do you think about a text field with input mask?
I am not a fan of input masks. Some implementations use the
valueof the field, which can be confusing for screen reader users (including sighted SR users). Some use the
placeholderattribute, which has the same problem and is sometimes invisible to low-vision users. Most display characters that are disallowed or otherwise skip over those characters, which can be problematic for those with mobility or cognitive impairments. I have seen users struggle with them in nearly every case where I have tested them.
Hi, thanks for the post. I really cannot believe that there is not an off-the-shelf option to have a field that captures known dates (like birth date).
I understand the datepicker option for things like selecting flights or planning a future date but in data capture from something like a form.
I’ve tried bootstrap, asp.net, html etc and none seem to allow one to simply switch off the picker.
Have you considered releasing something like this?
Ken, why not
<input type="text">as I outline above in my example? Look for date validation in your framework of choice instead of relying on my sub-par script.
Nice post, I appreciate so thank you for it!
I am a teacher of blind users and students and I have problem with the dates everydaily.
So I assume that js validation script moves to next apropriate day and month.
Could it be fixed?
I it will be very useful for blind users that could be confused and to enter wrond data in forms.
Iliya, the script I wrote is not production-ready. For example, as you discovered, it tries to convert the string to a valid date, which in this case it does.
If you are hoping to implement it or something similar in your own project, I suggest you work with a developer on the project to write a script that does what you need. There may already be something in their library that can do it.