Upgrading to v9
DayPicker v9 includes significant updates to accessibility, styles, internationalization, and performance. If your app is on v8, you can usually upgrade in one pass by updating the package, CSS imports, controlled selection, custom styles, and any custom components.
See the changelog for the full list of changes.
Upgrading from v7
If you are upgrading from v7 or earlier, first follow the migration guide from v7 to v8, then follow this guide.
Upgrade checklist
Most apps can migrate in this order:
- Upgrade the package: install the latest
react-day-pickerpackage. - Update CSS imports and styles: replace v8 CSS imports, CSS variables, class names, and
styleskeys. - Add
onSelectwhen usingselected: make controlled selections explicit. - Replace navigation boundary props: move from
from*andto*props tostartMonth,endMonth, andhidden. - Update custom components: replace renamed component slots.
- Update formatters, labels, and tests: return strings from formatters and update ARIA label overrides or assertions.
- Replace deprecated aliases and types: remove names kept only for compatibility.
If your app wraps DayPicker in a shared Calendar or DatePicker component, update that wrapper first, then check the screens that use it.
1. Upgrade the package
Install the latest v9 release:
- npm
- Yarn
- pnpm
- Bun
npm install react-day-picker@latest
yarn add react-day-picker@latest
pnpm add react-day-picker@latest
bun add react-day-picker@latest
If your app installed date-fns only because v8 required it as a peer dependency, you can remove it. Keep date-fns if you use it directly, for example for formatting dates or passing locales from date-fns/locale.
- npm
- Yarn
- pnpm
- Bun
npm remove date-fns
yarn remove date-fns
pnpm remove date-fns
bun remove date-fns
2. Update CSS imports and styles
Replace the v8 bundled CSS import:
- import "react-day-picker/dist/style.css";
+ import "react-day-picker/style.css";
If you import the CSS module, update that import path as well:
- import classNames from "react-day-picker/dist/style.module.css";
+ import classNames from "react-day-picker/style.module.css";
The default CSS and the rendered markup changed in v9. If you only import DayPicker's default CSS and do not override it, updating the CSS import path may be enough. If your app has custom CSS selectors, CSS variables, classNames, or styles, review them carefully.
Common style updates:
- CSS variables are now scoped under
.rdp-root. Move overrides there if they were previously set on:rootor.rdp. - The old
dayelement is nowday_button; the oldcellelement is nowday. - Class names for several UI elements and day states changed.
Example class name prop update:
<DayPicker
classNames={{
- day_disabled: "day-disabled",
+ disabled: "day-disabled",
}}
/>
Example day cell and button update:
<DayPicker
classNames={{
- cell: "day-cell",
+ day: "day-cell",
- day: "day-button",
+ day_button: "day-button",
}}
/>
Example CSS selector update:
-.rdp-day_selected {
+.rdp-selected {
font-weight: bold;
}
-.rdp-cell {
+.rdp-day {
padding: 0;
}
-.rdp-day {
+.rdp-day_button {
border-radius: 999px;
}
Class name changes from v8
| Old name | New name |
|---|---|
button | button_previous, button_next |
button_reset | button_previous, button_next |
caption | month_caption |
caption_between | Removed |
caption_dropdowns | dropdowns |
caption_end | Removed |
caption_start | Removed |
cell | day |
day | day_button |
day_disabled | disabled |
day_hidden | hidden |
day_outside | outside |
day_range_end | range_end |
day_range_middle | range_middle |
day_range_start | range_start |
day_selected | selected |
day_today | today |
dropdown_icon | chevron |
dropdown_month | months_dropdown |
dropdown_year | years_dropdown |
head | Removed |
head_cell | weekday |
head_row | weekdays |
multiple_months | Removed. Use the data-multiple-months data attribute. |
nav_button | button_previous, button_next |
nav_button_next | button_next |
nav_button_previous | button_previous |
nav_icon | chevron, button_next, button_previous |
row | week |
table | month_grid |
tbody | weeks |
tfoot | footer |
vhidden | Removed |
weeknumber | week_number |
with_weeknumber | Removed. Use the data-week-numbers data attribute. |
See the current class name keys in the UI enum.
3. Add onSelect when using selected
When you pass selected, DayPicker expects you to handle selection changes with onSelect. Add state in your component and pass the state setter or a custom handler.
+ const [selected, setSelected] = useState<Date | undefined>(undefined);
<DayPicker
mode="single"
selected={selected}
+ onSelect={setSelected}
/>
The same rule applies to mode="multiple" and mode="range":
const [range, setRange] = useState<DateRange | undefined>();
<DayPicker mode="range" selected={range} onSelect={setRange} />;
If you only need to mark days visually and do not want DayPicker to manage a selection mode, use custom modifiers instead of selected.
4. Replace navigation boundary props
The old navigation boundary props are deprecated in v9. Replace them with startMonth, endMonth, and hidden so your app is ready for v10.
| Deprecated prop | Use instead |
|---|---|
fromMonth | startMonth |
fromYear | startMonth with the first month of that year |
toMonth | endMonth |
toYear | endMonth with the last month of that year |
fromDate | hidden with a before matcher, and optionally startMonth |
toDate | hidden with an after matcher, and optionally endMonth |
Replace year boundaries:
<DayPicker
- fromYear={2010}
- toYear={2021}
+ startMonth={new Date(2010, 0)}
+ endMonth={new Date(2021, 11)}
/>
Replace month boundaries:
<DayPicker
- fromMonth={new Date(2010, 0)}
- toMonth={new Date(2021, 11)}
+ startMonth={new Date(2010, 0)}
+ endMonth={new Date(2021, 11)}
/>
Replace date boundaries:
<DayPicker
- fromDate={new Date(2010, 11, 3)}
+ startMonth={new Date(2010, 11)}
+ hidden={{ before: new Date(2010, 11, 3) }}
/>
<DayPicker
- toDate={new Date(2010, 11, 3)}
+ endMonth={new Date(2010, 11)}
+ hidden={{ after: new Date(2010, 11, 3) }}
/>
Use both startMonth or endMonth and hidden when you need to limit navigation and hide individual days outside the allowed range.
5. Update custom components
If you use the components prop, update custom component names and props.
Navigation icons now use one Chevron component:
<DayPicker
components={{
- IconRight: MyRightIcon,
- IconLeft: MyLeftIcon,
+ Chevron: (props) => {
+ if (props.orientation === "left") {
+ return <ChevronLeftIcon {...props} />;
+ }
+ return <ChevronRightIcon {...props} />;
+ },
}}
/>
Component changes from v8
| v8 component | v9 replacement |
|---|---|
Caption | MonthCaption |
Day | Still available, but interactive days now render a DayButton. |
DayContent | Removed. Use formatDay for text content, or customize DayButton. |
Head | Removed |
HeadRow | Weekdays |
IconDropdown | Removed. Use Chevron. |
IconLeft | Removed. Use Chevron. |
IconRight | Removed. Use Chevron. |
Row | Week |
See the custom components guide for details.
6. Update formatters, labels, and tests
Formatters now return strings. If a v8 formatter returned a React element, move the React rendering into a custom component.
<DayPicker
formatters={{
- formatCaption: (month) => <strong>{format(month, "LLLL y")}</strong>,
+ formatCaption: (month) => format(month, "LLLL y"),
}}
/>
Use a custom component when you need React markup:
<DayPicker
formatters={{
formatCaption: (month) => format(month, "LLLL y"),
}}
components={{
CaptionLabel: ({ children, ...props }) => (
<span {...props}>
<strong>{children}</strong>
</span>
),
}}
/>
Rename formatter and label aliases:
| Deprecated API | Use instead |
|---|---|
formatMonthCaption | formatCaption |
formatYearCaption | formatYearDropdown |
labelDay | labelDayButton |
labelCaption | labelGrid |
DayPicker's ARIA labels changed for accessibility. Update label overrides, translations, and tests that query buttons by accessible name.
| Label | Old label | New label |
|---|---|---|
labelDayButton | 21st November (Monday) | Monday, November 21st, 2024Monday, November 21st, 2024, selectedToday, November 21st, 2024 |
labelPrevious | Go to previous month | Go to the Previous Month |
labelNext | Go to next month | Go to the Next Month |
labelWeekNumber | Week nr. ## | Week ## |
Update test selectors as needed:
- screen.getByRole("button", { name: "Go to next month" });
+ screen.getByRole("button", { name: "Go to the Next Month" });
7. Replace deprecated aliases and types
Several v8 names still work in v9 for compatibility, but they are deprecated. Replace them with the current names before upgrading to v10.
Deprecated utility aliases
| Deprecated API | Use instead |
|---|---|
isMatch | dateMatchModifiers |
isDateInRange | rangeIncludesDate |
Deprecated TypeScript names
If you use TypeScript, replace deprecated v8 type names with the shorter current names.
- import type { DayPickerDefaultProps } from "react-day-picker";
+ import type { PropsBase } from "react-day-picker";
TypeScript type changes from v8
| Deprecated type | Use instead |
|---|---|
Caption | MonthCaption |
CaptionProps | MonthCaptionProps |
HeadRow | Removed |
Row | Week |
RowProps | WeekProps |
DayPickerSingleProps | PropsSingle |
DayPickerMultipleProps | PropsMulti |
DayPickerRangeProps | PropsRange |
DayPickerDefaultProps | PropsBase, or a more specific prop type |
DaySelectionMode | Mode |
Modifier | string |
InternalModifier | DayFlag or SelectionState |
SelectSingleEventHandler | PropsSingle["onSelect"] |
SelectMultipleEventHandler | PropsMulti["onSelect"] |
SelectRangeEventHandler | PropsRange["onSelect"] |
DayPickerProviderProps | Removed |
useNavigation | useDayPicker |
useDayRender | A custom Day or DayButton component |
ContextProvidersProps | Removed |
DayLabel | typeof labelDayButton |
NavButtonLabel | typeof labelNext or typeof labelPrevious |
WeekdayLabel | typeof labelWeekday |
WeekNumberLabel | typeof labelWeekNumber |
DayClickEventHandler | DayEventHandler<React.MouseEvent> |
DayFocusEventHandler | DayEventHandler<React.FocusEvent | React.KeyboardEvent> |
DayKeyboardEventHandler | DayEventHandler<React.KeyboardEvent> |
DayMouseEventHandler | DayEventHandler<React.MouseEvent> |
DayPointerEventHandler | DayEventHandler<React.PointerEvent> |
DayTouchEventHandler | DayEventHandler<React.TouchEvent> |
Useful search patterns
Use these patterns to find the most common v8 code that needs review:
rg "react-day-picker/dist/style|react-day-picker/dist/style.module|fromDate|toDate|fromMonth|toMonth|fromYear|toYear"
rg "selected=|initialFocus|onWeekNumberClick|onDayKeyUp|onDayKeyPress|onDayPointerEnter|onDayPointerLeave|onDayTouch"
rg "day_selected|day_disabled|day_today|day_range_|cell|table|tbody|head_cell|nav_button"
rg "IconLeft|IconRight|IconDropdown|DayContent|Caption|HeadRow|Row"
rg "formatMonthCaption|formatYearCaption|labelDay|labelCaption|isMatch|isDateInRange"
rg "DayPickerSingleProps|DayPickerMultipleProps|DayPickerRangeProps|DayPickerDefaultProps|useNavigation|useDayRender"