Repository: gpbl/react-day-picker
Pull request #2694 (2025-03-01 15:33:01)

docs: update for new `animate` prop
- added docs and playground
- renamed keyframes
- add `AnimationCustom` example (still not working well for weeks animation)

gpbl: @rodgobbi I’ve removed the “Advanced Animation” example. To properly customize animations, we’ll need to modify the HTML structure since the HTML Table isn’t working well with overflows.

I’ve also adjusted the class names based on your feedback - I appreciate your help there!
rodgobbi: > @rodgobbi I’ve removed the “Advanced Animation” example. To properly customize animations, we’ll need to modify the HTML structure since the HTML Table isn’t working well with overflows.
> 
> I’ve also adjusted the class names based on your feedback - I appreciate your help there!

Thanks!

And it makes sense to remove the up and down example, it's tricky to do it with the current HTML structure, adding any wrapper for trying to properly set `overflow` for up and down breaks the layout.

Fortunately, the default animation has no issues.


Patch:
diff --git a/examples/AnimateCSSVars.tsx b/examples/AnimateCSSVars.tsx
new file mode 100644
index 000000000..97d86c9f9
--- /dev/null
+++ b/examples/AnimateCSSVars.tsx
@@ -0,0 +1,19 @@
+import React from "react";
+
+import { DayPicker } from "react-day-picker";
+
+export function AnimateCSSVars() {
+  return (
+    <>
+      <style>
+        {`
+        .custom-animate {
+          --rdp-animation_duration: .1s;
+          --rdp-animation_timing: ease-in;
+          }
+        `}
+      </style>
+      <DayPicker className="custom-animate" animate />
+    </>
+  );
+}
diff --git a/examples/AnimateRtl.tsx b/examples/AnimateRtl.tsx
index 00dc0e87b..4617d4b8e 100644
--- a/examples/AnimateRtl.tsx
+++ b/examples/AnimateRtl.tsx
@@ -1,5 +1,6 @@
 import React, { useState } from "react";
 
+import { ar } from "date-fns/locale";
 import { DayPicker } from "react-day-picker";
 import classNames from "react-day-picker/style.module.css";
 
@@ -9,14 +10,12 @@ export function AnimateRtl() {
   return (
     <DayPicker
       mode="single"
+      locale={ar}
       animate
       dir="rtl"
       selected={selected}
       onSelect={setSelected}
       classNames={classNames}
-      footer={
-        selected ? `Selected: ${selected.toLocaleDateString()}` : "Pick a day."
-      }
     />
   );
 }
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/Start.tsx b/examples/Start.tsx
index a18d130dd..e1dac151f 100644
--- a/examples/Start.tsx
+++ b/examples/Start.tsx
@@ -7,6 +7,7 @@ export function Start() {
 
   return (
     <DayPicker
+      animate
       mode="single"
       selected={selected}
       onSelect={setSelected}
diff --git a/examples/index.ts b/examples/index.ts
index ba5486381..a4d9bdd2a 100644
--- a/examples/index.ts
+++ b/examples/index.ts
@@ -2,6 +2,7 @@ export * from "./AccessibleDatePicker";
 export * from "./Animate";
 export * from "./AnimateRange";
 export * from "./AnimateRtl";
+export * from "./AnimateCSSVars";
 export * from "./AutoFocus";
 export * from "./BroadcastCalendar";
 export * from "./ContainerAttributes";
@@ -18,6 +19,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
diff --git a/src/UI.ts b/src/UI.ts
index 3535ca07e..2faac7988 100644
--- a/src/UI.ts
+++ b/src/UI.ts
@@ -101,23 +101,27 @@ export enum SelectionState {
 }
 
 /** CSS classes used for animating months and captions. */
+/**
+ * Enum representing different animation states for transitioning between
+ * months.
+ */
 export enum Animation {
-  /** Applied to the entering month when it is after the exiting month. */
-  weeks_next_enter = "weeks_next_enter",
-  /** Applied to the entering month when it is before the exiting month. */
-  weeks_prev_enter = "weeks_prev_enter",
-  /** Applied to the exiting month when it is after the entering month. */
-  weeks_next_exit = "weeks_next_exit",
-  /** Applied to the exiting month when it is before the entering month. */
-  weeks_prev_exit = "weeks_prev_exit",
-  /** Applied to the entering month caption when it is after the exiting month. */
-  caption_next_enter = "caption_next_enter",
-  /** Applied to the entering month caption when it is before the exiting month. */
-  caption_prev_enter = "caption_prev_enter",
-  /** Applied to the exiting month caption when it is after the entering month. */
-  caption_next_exit = "caption_next_exit",
-  /** Applied to the exiting month caption when it is before the entering month. */
-  caption_prev_exit = "caption_prev_exit"
+  /** The entering weeks when they appear before the exiting month. */
+  weeks_before_enter = "weeks_before_enter",
+  /** The exiting weeks when they disappear before the entering month. */
+  weeks_before_exit = "weeks_before_exit",
+  /** The entering weeks when they appear after the exiting month. */
+  weeks_after_enter = "weeks_after_enter",
+  /** The exiting weeks when they disappear after the entering month. */
+  weeks_after_exit = "weeks_after_exit",
+  /** The entering caption when it appears after the exiting month. */
+  caption_after_enter = "caption_after_enter",
+  /** The exiting caption when it disappears after the entering month. */
+  caption_after_exit = "caption_after_exit",
+  /** The entering caption when it appears before the exiting month. */
+  caption_before_enter = "caption_before_enter",
+  /** The exiting caption when it disappears before the entering month. */
+  caption_before_exit = "caption_before_exit"
 }
 
 /**
diff --git a/src/style.css b/src/style.css
index 4d8b1cac2..e5c185968 100644
--- a/src/style.css
+++ b/src/style.css
@@ -342,42 +342,42 @@
   }
 }
 
-.rdp-weeks_next_enter {
-  animation: rdp-slide_in_right var(--rdp-animation_duration)
+.rdp-weeks_before_enter {
+  animation: rdp-slide_in_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-weeks_prev_exit {
+.rdp-weeks_before_exit {
   animation: rdp-slide_out_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-weeks_prev_enter {
-  animation: rdp-slide_in_left var(--rdp-animation_duration)
+.rdp-weeks_after_enter {
+  animation: rdp-slide_in_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-weeks_next_exit {
+.rdp-weeks_after_exit {
   animation: rdp-slide_out_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .rdp-weeks_next_enter {
+.rdp-root[dir="rtl"] .rdp-weeks_after_enter {
   animation: rdp-slide_in_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .rdp-weeks_prev_exit {
+.rdp-root[dir="rtl"] .rdp-weeks_before_exit {
   animation: rdp-slide_out_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .rdp-weeks_prev_enter {
+.rdp-root[dir="rtl"] .rdp-weeks_before_enter {
   animation: rdp-slide_in_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .rdp-weeks_next_exit {
+.rdp-root[dir="rtl"] .rdp-weeks_after_exit {
   animation: rdp-slide_out_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
@@ -400,22 +400,22 @@
   }
 }
 
-.rdp-caption_next_enter {
+.rdp-caption_after_enter {
   animation: rdp-fade_in var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-caption_prev_exit {
+.rdp-caption_after_exit {
   animation: rdp-fade_out var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-caption_prev_enter {
+.rdp-caption_before_enter {
   animation: rdp-fade_in var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.rdp-caption_next_exit {
+.rdp-caption_before_exit {
   animation: rdp-fade_out var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
diff --git a/src/style.module.css b/src/style.module.css
index 4c4bd60dd..6f95ba96b 100644
--- a/src/style.module.css
+++ b/src/style.module.css
@@ -342,42 +342,42 @@
   }
 }
 
-.weeks_next_enter {
-  animation: rdp-slide_in_right var(--rdp-animation_duration)
+.weeks_before_enter {
+  animation: rdp-slide_in_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.weeks_prev_exit {
+.weeks_before_exit {
   animation: rdp-slide_out_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.weeks_prev_enter {
-  animation: rdp-slide_in_left var(--rdp-animation_duration)
+.weeks_after_enter {
+  animation: rdp-slide_in_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.weeks_next_exit {
+.weeks_after_exit {
   animation: rdp-slide_out_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .weeks_next_enter {
+.root[dir="rtl"] .weeks_after_enter {
   animation: rdp-slide_in_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .weeks_prev_exit {
+.root[dir="rtl"] .weeks_before_exit {
   animation: rdp-slide_out_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .weeks_prev_enter {
+.root[dir="rtl"] .weeks_before_enter {
   animation: rdp-slide_in_right var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-[dir="rtl"] .weeks_next_exit {
+.root[dir="rtl"] .weeks_after_exit {
   animation: rdp-slide_out_left var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
@@ -400,22 +400,22 @@
   }
 }
 
-.caption_next_enter {
+.caption_after_enter {
   animation: rdp-fade_in var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.caption_prev_exit {
+.caption_after_exit {
   animation: rdp-fade_out var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.caption_prev_enter {
+.caption_before_enter {
   animation: rdp-fade_in var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
 
-.caption_next_exit {
+.caption_before_exit {
   animation: rdp-fade_out var(--rdp-animation_duration)
     var(--rdp-animation_timing) forwards;
 }
diff --git a/src/types/props.ts b/src/types/props.ts
index cd3fb2931..9ec90752a 100644
--- a/src/types/props.ts
+++ b/src/types/props.ts
@@ -246,9 +246,11 @@ export interface PropsBase {
    */
   showWeekNumber?: boolean;
   /**
-   * Animate navigating between months.
+   * Experimental. Animate navigating between months.
    *
-   * @see https://daypicker.dev/docs/customization#animation
+   * @since 9.6.0
+   * @experimental
+   * @see https://daypicker.dev/docs/navigation#animate
    */
   animate?: boolean;
   /**
diff --git a/src/useAnimation.ts b/src/useAnimation.ts
index 1f16163f5..e0fd45f2f 100644
--- a/src/useAnimation.ts
+++ b/src/useAnimation.ts
@@ -121,12 +121,12 @@ export function useAnimation(
 
         // animate new displayed month
         const captionAnimationClass = isAfterPreviousMonth
-          ? classNames[Animation.caption_next_enter]
-          : classNames[Animation.caption_prev_enter];
+          ? classNames[Animation.caption_after_enter]
+          : classNames[Animation.caption_before_enter];
 
         const weeksAnimationClass = isAfterPreviousMonth
-          ? classNames[Animation.weeks_next_enter]
-          : classNames[Animation.weeks_prev_enter];
+          ? classNames[Animation.weeks_after_enter]
+          : classNames[Animation.weeks_before_enter];
 
         currentMonthEl.style.position = "relative";
         currentMonthEl.style.overflow = "hidden";
@@ -179,8 +179,8 @@ export function useAnimation(
         if (previousCaptionEl && previousCaptionEl instanceof HTMLElement) {
           previousCaptionEl.classList.add(
             isAfterPreviousMonth
-              ? classNames[Animation.caption_prev_exit]
-              : classNames[Animation.caption_next_exit]
+              ? classNames[Animation.caption_before_exit]
+              : classNames[Animation.caption_after_exit]
           );
           previousCaptionEl.addEventListener("animationend", cleanUp);
         }
@@ -191,8 +191,8 @@ export function useAnimation(
         if (previousWeeksEl && previousWeeksEl instanceof HTMLElement) {
           previousWeeksEl.classList.add(
             isAfterPreviousMonth
-              ? classNames[Animation.weeks_prev_exit]
-              : classNames[Animation.weeks_next_exit]
+              ? classNames[Animation.weeks_before_exit]
+              : classNames[Animation.weeks_after_exit]
           );
         }
 
diff --git a/website/docs/docs/navigation.mdx b/website/docs/docs/navigation.mdx
index ba0aacefe..64baeadf4 100644
--- a/website/docs/docs/navigation.mdx
+++ b/website/docs/docs/navigation.mdx
@@ -88,6 +88,55 @@ Limit the dates the user can navigate to by using the `startMonth` and `endMonth
   <Examples.StartEndMonths />
 </BrowserWindow>
 
+## Animating Month Transitions {#animate}
+
+To animate the transition between months, set the `animate` prop to `true`:
+
+| Prop Name | Type      | Description                                                     |
+| --------- | --------- | --------------------------------------------------------------- |
+| `animate` | `boolean` | Enable the transition animation when navigating between months. |
+
+```tsx
+<DayPicker animate />
+```
+
+<BrowserWindow>
+  <Examples.Animate />
+</BrowserWindow>
+
+:::warning Experimental Feature
+
+The `animate` prop is experimental and may change in the future. Please note that advanced animations may be limited by the table HTML structure. Please report any issues in the [GitHub Discussions](https://github.com/gpbl/react-day-picker/discussions).
+
+:::
+
+### Customizing the Animation
+
+Use the supported CSS variables to customize the animation duration or timing function:
+
+```css
+.custom-animate {
+  --rdp-animation_duration: 0.1s; /* Change the duration of the transition. */
+  --rdp-animation_timing: ease-in; /* Choose a different timing function. */
+}
+```
+
+```tsx
+<DayPicker animate className="custom-animate" />
+```
+
+### Accessibility Note
+
+To improve accessibility for users who prefer reduced motion, you can use the `prefers-reduced-motion` media query to disable animations.
+
+```css
+@media (prefers-reduced-motion: reduce) {
+  .custom-animate {
+    --rdp-animation_duration: 0s;
+  }
+}
+```
+
 ## Disabling the Navigation {#disablenavigation}
 
 To prevent the user from navigating between months, set the `disableNavigation` prop to `true`.
diff --git a/website/docs/docs/styling.mdx b/website/docs/docs/styling.mdx
index 4452719fc..d2c2647e7 100644
--- a/website/docs/docs/styling.mdx
+++ b/website/docs/docs/styling.mdx
@@ -81,6 +81,29 @@ The following table lists the CSS variables used by DayPicker within the `.rdp-r
         The accent background color used for selected days and UI elements.
       </td>
     </tr>
+    <tr>
+      <td>
+        <code>--rdp-animation_duration</code>
+      </td>
+      <td>
+        The duration of the animation when `animate` is set (default: `0.3s`).
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>--rdp-animation_timing</code>
+      </td>
+      <td>
+        The timing function when `animate` is set (default: `cubic-bezier(0.4,
+        0, 0.2, 1)`.
+      </td>
+    </tr>
+    <tr>
+      <td>
+        <code>--rdp-day-height</code>
+      </td>
+      <td>The height of the day cells (default: `44px`).</td>
+    </tr>
     <tr>
       <td>
         <code>--rdp-day-height</code>
diff --git a/website/docs/intro.mdx b/website/docs/intro.mdx
index 17b737998..521168ac5 100644
--- a/website/docs/intro.mdx
+++ b/website/docs/intro.mdx
@@ -33,6 +33,7 @@ function MyDatePicker() {
 
   return (
     <DayPicker
+      animate
       mode="single"
       selected={selected}
       onSelect={setSelected}
diff --git a/website/docs/start.mdx b/website/docs/start.mdx
index 4484d35b3..bb59ddce0 100644
--- a/website/docs/start.mdx
+++ b/website/docs/start.mdx
@@ -31,6 +31,7 @@ export function MyDatePicker() {
 
   return (
     <DayPicker
+      animate
       mode="single"
       selected={selected}
       onSelect={setSelected}
diff --git a/website/src/components/Playground/index.tsx b/website/src/components/Playground/index.tsx
index de04bf9c6..e209fe01d 100644
--- a/website/src/components/Playground/index.tsx
+++ b/website/src/components/Playground/index.tsx
@@ -267,6 +267,17 @@ export function Playground() {
                 Paged Navigation
               </label>
             )}
+            <label>
+              <input
+                type="checkbox"
+                name="animate"
+                checked={props.animate}
+                onChange={(e) =>
+                  setProps({ ...props, animate: e.target.checked })
+                }
+              />
+              Animate
+            </label>
             <label>
               <input
                 type="checkbox"


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"
   );
 });
diff --git a/src/helpers/getDefaultClassNames.test.ts b/src/helpers/getDefaultClassNames.test.ts
index af7d43d7b..5891ef07c 100644
--- a/src/helpers/getDefaultClassNames.test.ts
+++ b/src/helpers/getDefaultClassNames.test.ts
@@ -35,13 +35,13 @@ test("should return the default classnames", () => {
     weekday: "rdp-weekday",
     weekdays: "rdp-weekdays",
     years_dropdown: "rdp-years_dropdown",
-    caption_next_enter: "rdp-caption_next_enter",
-    caption_prev_enter: "rdp-caption_prev_enter",
-    weeks_next_enter: "rdp-weeks_next_enter",
-    weeks_prev_enter: "rdp-weeks_prev_enter",
-    caption_next_exit: "rdp-caption_next_exit",
-    caption_prev_exit: "rdp-caption_prev_exit",
-    weeks_next_exit: "rdp-weeks_next_exit",
-    weeks_prev_exit: "rdp-weeks_prev_exit"
+    caption_after_enter: "rdp-caption_after_enter",
+    caption_after_exit: "rdp-caption_after_exit",
+    caption_before_enter: "rdp-caption_before_enter",
+    caption_before_exit: "rdp-caption_before_exit",
+    weeks_after_enter: "rdp-weeks_after_enter",
+    weeks_after_exit: "rdp-weeks_after_exit",
+    weeks_before_enter: "rdp-weeks_before_enter",
+    weeks_before_exit: "rdp-weeks_before_exit"
   });
 });
diff --git a/src/useAnimation.test.tsx b/src/useAnimation.test.tsx
index 7f90928a4..a83d49fdf 100644
--- a/src/useAnimation.test.tsx
+++ b/src/useAnimation.test.tsx
@@ -76,14 +76,14 @@ describe("useAnimation", () => {
       await user.click(nextButton());
 
       expect(getMonthCaptionContainers()[0]).toHaveClass(
-        "rdp-caption_prev_exit"
+        "rdp-caption_before_exit"
       );
       expect(getMonthCaptionContainers()[1]).toHaveClass(
-        "rdp-caption_next_enter"
+        "rdp-caption_after_enter"
       );
 
-      expect(getMonthWeeksContainers()[0]).toHaveClass("rdp-weeks_prev_exit");
-      expect(getMonthWeeksContainers()[1]).toHaveClass("rdp-weeks_next_enter");
+      expect(getMonthWeeksContainers()[0]).toHaveClass("rdp-weeks_before_exit");
+      expect(getMonthWeeksContainers()[1]).toHaveClass("rdp-weeks_after_enter");
     });
 
     it("should apply the correct animation class when entering month is before the exiting month", async () => {
@@ -92,14 +92,16 @@ describe("useAnimation", () => {
       await user.click(previousButton());
 
       expect(getMonthCaptionContainers()[0]).toHaveClass(
-        "rdp-caption_next_exit"
+        "rdp-caption_after_exit"
       );
       expect(getMonthCaptionContainers()[1]).toHaveClass(
-        "rdp-caption_prev_enter"
+        "rdp-caption_before_enter"
       );
 
-      expect(getMonthWeeksContainers()[0]).toHaveClass("rdp-weeks_next_exit");
-      expect(getMonthWeeksContainers()[1]).toHaveClass("rdp-weeks_prev_enter");
+      expect(getMonthWeeksContainers()[0]).toHaveClass("rdp-weeks_after_exit");
+      expect(getMonthWeeksContainers()[1]).toHaveClass(
+        "rdp-weeks_before_enter"
+      );
     });
 
     it("should clean up the exiting month after animation ends", async () => {
@@ -121,11 +123,11 @@ describe("useAnimation", () => {
       expect(getMonthWeeksContainers()).toHaveLength(1);
 
       expect(getMonthCaptionContainers()[0]).not.toHaveClass(
-        "rdp-caption_next_enter"
+        "rdp-caption_after_enter"
       );
 
       expect(getMonthWeeksContainers()[0]).not.toHaveClass(
-        "rdp-weeks_next_enter"
+        "rdp-weeks_after_enter"
       );
     });
   });
diff --git a/src/useDayPicker.test.tsx b/src/useDayPicker.test.tsx
index 9d70e6ba9..7029fe478 100644
--- a/src/useDayPicker.test.tsx
+++ b/src/useDayPicker.test.tsx
@@ -88,14 +88,14 @@ describe("useDayPicker", () => {
       [DayFlag.outside]: "",
       [DayFlag.focused]: "",
       [DayFlag.today]: "",
-      [Animation.weeks_next_enter]: "",
-      [Animation.weeks_prev_exit]: "",
-      [Animation.weeks_prev_enter]: "",
-      [Animation.weeks_next_exit]: "",
-      [Animation.caption_next_enter]: "",
-      [Animation.caption_prev_exit]: "",
-      [Animation.caption_prev_enter]: "",
-      [Animation.caption_next_exit]: ""
+      [Animation.weeks_after_enter]: "",
+      [Animation.weeks_before_exit]: "",
+      [Animation.weeks_before_enter]: "",
+      [Animation.weeks_after_exit]: "",
+      [Animation.caption_after_enter]: "",
+      [Animation.caption_before_exit]: "",
+      [Animation.caption_before_enter]: "",
+      [Animation.caption_after_exit]: ""
     },
     styles: {},
     labels: {