I have the following datepicker. The problem is that when running screen reader (NVDA), when moving the selection on the datepicker grid to different cells using keyboard, the screen reader just says "blank". (However, if I hover over the cells with mouse, it does read the number of the day correctly.)
$(document).ready(function () {
$('#ui-datepicker-div').addClass("month-calendar-widget");
$(".month-calendar input").datepicker({
showOtherMonths: true,
minDate: 0,
beforeShow: function () {
$('#ui-datepicker-div').addClass("month-calendar-widget");
}
}).datepicker("setDate", convertDateToUTC(new Date()));
});
What I was hoping was to fix this issue by adding aria-label attribute to each cell of the grid using beforeShowDay like below:
beforeShowDay: function(date) {
var dateString = $.datepicker.formatDate('MM d, yy', date);
return [true, '', dateString + "" + 'aria-label="' + dateString + '" role="gridcell" aria-selected="false"'];
}
However, this results in the follwing html which is wrong:
<td class=" " data-event="click" data-handler="selectDay" data-month="1" data-year="2024" title="February 16, 2024aria-label="February 16, 2024" role="gridcell" aria-selected="false"">
<a class="ui-state-default" href="#">16</a>
</td>
What am I missing?
Update 1:
To further clarify, here is my goal:
- Run NVDA (just google
nvda downloadand download and run it) - Navigate to, for example, the datepicker Diego provided in his answer below, then using keyboard move to different cells in the grid:

- I am expecting NVDA say the date, but it just says "blank".
update 2
Use this jsfiddle to play with Diego's answer
update 3
After further investigation, I think there is a fundamental issue with regard to accessibility of this JQuery datepicker: basically, imagine you cannot visually see the page and you tab into that field. Now there are two simultaneous options to enter the date: both by typing and moving across the datepicker grid. This is also probably why the screen-reader is confused too. I think the two options should have separate triggers: i.e. we have a text box where user can enter text, AND a button that is when clicked, opens the date picker where the user can now select a date. I looked some other implementations of the date-picker and they all seem to have implemented it this way. I also found this github issue for the same: https://github.com/jquery/jquery-ui/issues/2155
Since beforeShowDay supports only creating the value of the
titleattribute, and since the trick of closing the quote to add your further attribute may not be enough because it's addressing a td and not the interactive element, you may just use a different strategy to populate thearia-labelattribute on the actual anchor.You can rely on the option
beforeShowthat will run the function given just one moment before the datepicker is actually shown:https://api.jqueryui.com/datepicker/#option-beforeShow
Such function will iterate over each interactive element inside the calendar containing every single day the user can pick (anchor element) and will add an
aria-labelattribute to it with the value coming from thetitleattribute on its parent cell (set bybeforeShowDayas you did).This is an example of a day cell being processed:
There was the option of crafting the date by picking its parts from each component like this, but it was overkill:
As a further action I also dealt with the
onSelectevent that will add thearia-labelattribute also to the input element once a date was selected inside the datepicker. It could be not needed since probably screen readers already can read the value of an input element.Edit: as you found out with a library specifically designed to solve this particular problem, the datepicker doesn't move the focus while navigating over the calendar and it instead remains locked on the input field. That's why despite the 'aria-label` was set, it couldn't be read if the screenreader couldn't see the focus moving.
So the solution I provided here, so far, cannot fully address the scenario because it's missing the logics to deal with the focus.
That library I see instead is using a strategy based on the
tab-indexattribute andaria-selectcorrectly achieving that goal.I also used the option
showOnasbuttonso that the datepicker won't show up when the text input gained focus but only when the dedicated button is clicked.https://api.jqueryui.com/datepicker/#option-showOn