Repository: gpbl/react-day-picker
Pull request #2700 (2025-03-08 10:33:20)

fix: render selected days with selected modifier when disabled
Fixes issue https://github.com/gpbl/react-day-picker/issues/2699 by always applying the `selected` modifier if a day is part of the `selected` date.

Notes:
This fix reverts [this change](https://github.com/gpbl/react-day-picker/pull/2171/files#diff-16d85a5debbc177a4de5d5687ff4f6a4d5ed25ad909b77b50d6c22014a551727L75) from a previous fix PR.
What I understood from the context is that the main issue the referred PR fixes is that the disabled days were able to be clicked and selected, so displaying them as `selected` seems correct while ignoring click events coming from them.

Demo:

Tested rendering duplicated `DayPicker`s by rendering them `disabled`.

<img width="785" alt="Screenshot 2025-03-08 at 11 11 49" src="https://github.com/user-attachments/assets/0f79beed-c122-4572-b1e3-8c1d65a31d81" />

Added new example for testing the modifier customizations are applied:

<img width="357" alt="Screenshot 2025-03-08 at 11 25 45" src="https://github.com/user-attachments/assets/431c6729-4a97-4f86-bcd1-19ab1d8be96c" />



Patch:
diff --git a/examples/DisabledSelectedDate.tsx b/examples/DisabledSelectedDate.tsx
new file mode 100644
index 000000000..3ab064d51
--- /dev/null
+++ b/examples/DisabledSelectedDate.tsx
@@ -0,0 +1,31 @@
+import React from "react";
+
+import { DayPicker } from "react-day-picker";
+
+const today = new Date(2025, 2, 8);
+const toDate = new Date(today);
+toDate.setDate(toDate.getDate() + 3);
+
+/**
+ * Test case for issue #2699
+ *
+ * @see https://github.com/gpbl/react-day-picker/issues/2699
+ */
+export function DisabledSelectedDate() {
+  return (
+    <DayPicker
+      mode="range"
+      disabled
+      today={today}
+      modifiersStyles={{
+        selected: {
+          backgroundColor: "red"
+        }
+      }}
+      selected={{
+        from: today,
+        to: toDate
+      }}
+    />
+  );
+}
diff --git a/examples/index.ts b/examples/index.ts
index ba5486381..d355a0078 100644
--- a/examples/index.ts
+++ b/examples/index.ts
@@ -18,6 +18,7 @@ export * from "./CustomWeek";
 export * from "./DefaultMonth";
 export * from "./Dialog";
 export * from "./Disabled";
+export * from "./DisabledSelectedDate";
 export * from "./DisableNavigation";
 export * from "./Dropdown";
 export * from "./DropdownMonths";
diff --git a/src/DayPicker.tsx b/src/DayPicker.tsx
index b47f8aaf1..5c4509e36 100644
--- a/src/DayPicker.tsx
+++ b/src/DayPicker.tsx
@@ -480,8 +480,7 @@ export function DayPicker(props: DayPickerProps) {
                               Boolean(focused?.isEqualTo(day));
 
                             modifiers[SelectionState.selected] =
-                              !modifiers.disabled &&
-                              (isSelected?.(date) || modifiers.selected);
+                              isSelected?.(date) || modifiers.selected;
 
                             if (isDateRange(selectedValue)) {
                               // add range modifiers


Test patch:
diff --git a/examples/DisabledSelectedDate.test.tsx b/examples/DisabledSelectedDate.test.tsx
new file mode 100644
index 000000000..da8de656c
--- /dev/null
+++ b/examples/DisabledSelectedDate.test.tsx
@@ -0,0 +1,37 @@
+import React from "react";
+
+import { gridcell } from "@/test/elements";
+import { render } from "@/test/render";
+
+import { DisabledSelectedDate } from "./DisabledSelectedDate";
+
+test("selected days should render with 'selected' modifier when disabled", () => {
+  render(<DisabledSelectedDate />);
+
+  const dayBeforeRangeStart = new Date(2025, 2, 7);
+  expect(gridcell(dayBeforeRangeStart, true)).not.toHaveClass("rdp-selected");
+  expect(gridcell(dayBeforeRangeStart, true)).not.toHaveStyle(
+    "background-color: red"
+  );
+  const rangeStart = new Date(2025, 2, 8);
+  expect(gridcell(rangeStart, true)).toHaveClass("rdp-selected");
+  expect(gridcell(rangeStart, true)).toHaveStyle("background-color: red");
+
+  rangeStart.setDate(rangeStart.getDate() + 1);
+  expect(gridcell(rangeStart, true)).toHaveClass("rdp-selected");
+  expect(gridcell(rangeStart, true)).toHaveStyle("background-color: red");
+
+  rangeStart.setDate(rangeStart.getDate() + 1);
+  expect(gridcell(rangeStart, true)).toHaveClass("rdp-selected");
+  expect(gridcell(rangeStart, true)).toHaveStyle("background-color: red");
+
+  rangeStart.setDate(rangeStart.getDate() + 1);
+  expect(gridcell(rangeStart, true)).toHaveClass("rdp-selected");
+  expect(gridcell(rangeStart, true)).toHaveStyle("background-color: red");
+
+  rangeStart.setDate(rangeStart.getDate() + 1);
+  expect(gridcell(rangeStart, true)).not.toHaveClass("rdp-selected");
+  expect(gridcell(dayBeforeRangeStart, true)).not.toHaveStyle(
+    "background-color: red"
+  );
+});
diff --git a/examples/TestCase2047.test.tsx b/examples/TestCase2047.test.tsx
index 1c9094a6c..a194fe8f0 100644
--- a/examples/TestCase2047.test.tsx
+++ b/examples/TestCase2047.test.tsx
@@ -10,8 +10,8 @@ beforeEach(async () => {
   render(<TestCase2047 />);
 });
 
-test("disabled date is not selected", () => {
-  expect(gridcell(new Date(2024, 5, 10), true)).not.toHaveAttribute(
+test("disabled date renders with selected modifier", () => {
+  expect(gridcell(new Date(2024, 5, 10), true)).toHaveAttribute(
     "aria-selected"
   );
 });