This post is based on my research on proper markup and accessibility for date pickers, related to work on the WordPress Gutenberg project and has been adapted to a more broad audience.
A lot of the literature I could find online, as well as the free programming libraries and examples use outdated version of the WAI-ARIA Best Practices document, the newest version of which does not even mention date pickers.
So here I am, doing research — and I hope it will be useful for others as well.
To boil things down
- Do not make the user depend on using a date picker as a primary input method. Instead, use form input fields, with the date filter as an alternative. Provide live validation if the user is limited to certain dates.
- If the date picker does not provide functionality other than selecting a valid date, hide it from the screenreader context and tab index.
- If the date picker provides additional functionality, an alternative should be provided. Bonus points if the date picker can be the alternative instead.
Providing live validation
change event for each relevant input field.
aria-invalid attribute set to
true should be provided to indicate which input field has the invalid date. Once the input is valid again, the attribute is changed to
false or removed.
One may also want to provide a validation message with
role="status". This indicates to assistive devices such as screenreaders that the message is a “live area” and any updates are provided to the user as soon as the user is determined not to be busy.
<form id="booking_form" aria-controls="booking_validation_message"> <label> Date: <input id="booking_date" type="text" value="December 25 2018" aria-invalid="true" /> </label> <p id="booking_validation_message" class="invalid" role="status"> Sorry, we don't fly to London–Heathrow on the specified date. </p> </form>
In the case of multiple fields, one should either indicate the specific attribute if possible. When it can’t de determined which field is invalid, the aria-invalid attribute shuld be assigned to the relevant fieldset or the whole form.
<form id="booking_form" aria-controls="booking_validation_message"> <label> <input type="text" name="destination" value="London LHR" /> </label> <fieldset id="date_fields" aria-invalid="true"> <label> Day <input type="number" name="day" value="31" /> </label> <label> Month <select name="month"> <option value="1">January</option> <option value="2" selected="true">February</option> … </select> </label> <label> Year <input type="number" name="year" value="2018" /> </label> </fieldset> <p id="booking_validation_message" class="invalid" role="status"> The date provided is invalid. </p> </form>
Hiding from the screenreader context and tab index
The datepicker itself may be hidden away from the screenreader context and tab index by using the
aria-hidden attribute and setting the
tabindex attribute to a negative number like
This means that most navigation issues related to the date picker, like treading through the calendar or finding the next or previous month are simply averted by setting it a side, and only depending on the primary input methods.
In this example, JSX-like abstraction is used, so we can concentrate on the
<div> element, which contents are hidden away from.
<DateForm /> <div id="datepicker_popover" tabindex="-1" aria-hidden="true" /> <DatePicker /> </div>
Providing an alternative
In cases where the date picker provides added value like displaying the lowest price for a flight leg over a range of days or indicates the availability of your hairdresser at glance, I highly enoucrage the use of alternatives to a date picker.
A section using the
aria-describedby attribute may be used for a textual summary, while one using
aria-details may be use for finer details.
But still — sometimes accessibility issues are more closely related to human communications than to markup and techincal guidelines:
- A beach resort is fully booked during certain days. Is there a way to communicate that more clearly than inside the datepicker?
- Are there other ways to indicate the lowest fares for a given date range, then to display them in the datepicker itself?
- Your hairdresser is on vacation over a couple of weeks, and it is displayed in the date picker as a series of disabled dates. How can your hairdresser communicate this differently?