I am working on a React project where I need to make the DayPicker component accessible by adding dynamic aria-labels to individual day elements based on their state (e.g., selected, disabled, limited, or unavailable).
Here is the code I am currently using for the DayPicker
:
<DayPicker
mode="single"
selected={calendarDates.selected}
onDayClick={setDate}
showOutsideDays
disabled={{ before: startDate, after: endDate }}
modifiers={{
limited: calendarDates.limited,
unavailable: calendarDates.unavailable,
}}
modifiersStyles={{
limited: limitedStyle,
unavailable: unavailableStyle,
}}
/>
Problem Statement:
I want to:
- Add dynamic aria-labels to each day in the calendar based on its state (e.g., "Selected date: January 1, 2024", "Unavailable date: January 2, 2024").
- Ensure these aria-labels are accessible for screen readers.
What I Tried:
I attempted to use an ariaLabelFormatter prop, but it seems the library does not support it (Property ‘ariaLabelFormatter’ does not exist on type ‘DayPicker’).
I looked into using a renderDay prop, but it is also unavailable.
I tried post-render DOM manipulation using useRef and useEffect, like so:
useEffect(() => {
if (calendarRef.current) {
const days = calendarRef.current.querySelectorAll(".rdp-day"); // Adjusted selector
days.forEach((day) => {
const date = day.getAttribute("aria-label");
let ariaLabel = date;
if (day.classList.contains("rdp-day_selected")) {
ariaLabel = `Selected date: ${date}`;
} else if (day.classList.contains("rdp-day_disabled")) {
ariaLabel = `${date} is not available for selection.`;
}
day.setAttribute("aria-label", ariaLabel || date);
});
}
}, [calendarDates]);
However, this feels like a workaround and doesn’t seem reliable as it depends on class names and direct DOM manipulation. I am using the following versions:
1. "react": "^18.2.0",
2. "react-datepicker": "^6.6.0",
3. "react-day-picker": "^8.10.0",
2
Answers
As suggested in comments as well
Option 1: Upgrade to the latest package versions
Option 2: Stick with your
useEffect
implementation with classes as there is no risk of changingclassNames
if you are sticking to a specific version.react-day-picker
newest versions already offers you an API to customize which components to use while rendering. We can take advantage of it, by passing the defaultDay
component, or any other of your choose, and adding custom props.This
Day
key inside thecomponents
prop is a function, which takes the day and a set of modifiers. Inspect the signature for full reference. Inside the first parameter of that function, you can access the properties you are refering to, either the day is the selected one, is it today, is it disabled…Here’s a small piece on how you can archive your goal. The rest of the logic is up to you.
If you are using 8.x, then you only have the day itself, so you should handle all the validations by yourself: determine if the day is selected, disabled, etc.