skip to Main Content

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:

  1. 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").
  2. 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


  1. 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 changing classNames if you are sticking to a specific version.

    Login or Signup to reply.
  2. 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 default Day component, or any other of your choose, and adding custom props.

    This Day key inside the components 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.

    import { DayPicker, Day } from "react-day-picker";
    import "react-day-picker/style.css";
    
    export default function App() {
      return (
        <DayPicker
          mode="single"
          components={{
            Day: (props) => {
              const { disabled, selected, focused, hidden, outside, today } =
                props.modifiers;
    
              return (
                <Day
                  {...props}
                  {...(selected && {
                    ["aria-label"]: "Selected Date: " + props.day.date,
                  })}
                />
              );
            },
          }}
        />
      );
    }
    
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search