React DayPicker
React DayPicker is a highly customizable and accessible date picker component for React applications, currently at version 9.14.0. It offers extensive features for single, multiple, and range date selections, along with advanced localization capabilities supporting various calendar systems including ISO 8601, Persian, Hijri, Buddhist, Ethiopic, and Hebrew. The library is actively maintained with frequent minor and patch releases, indicating ongoing development and improvements. Key differentiators include its focus on accessibility (WCAG 2.1 AA compliant), flexible styling with CSS, robust timezone handling, and a modular architecture that allows for custom components and extensions. It ships with TypeScript types and is compiled to both CommonJS and ESM, making it suitable for modern React projects.
Common errors
-
TypeError: Cannot read properties of undefined (reading 'DayPicker') OR DayPicker is not a function
cause Attempting to use CommonJS `require` syntax with a package that primarily targets ES Modules or when the default export is not correctly accessed.fixEnsure you are using ES Module imports: `import { DayPicker } from 'react-day-picker';`. If server-side rendering with CommonJS, ensure your build setup correctly handles ESM or use a dynamic `import()` statement if supported by your runtime. While `react-day-picker` compiles to CommonJS, ES module imports are the recommended modern approach. -
DayPicker styles are not applied or look broken.
cause The default CSS stylesheet was not imported or the import path is incorrect, or custom CSS is overriding default styles unintentionally.fixEnsure you have `import 'react-day-picker/dist/style.css';` in your entry file or a relevant component. If upgrading from v7, note the path changed from `lib/style.css` to `dist/style.css`. Review custom CSS for conflicts. -
My custom input field loses focus when selecting a day from the DayPicker.
cause When integrating DayPicker with a custom input (especially after `DayPickerInput` was removed), the focus might not persist on the input after a selection due to React's re-rendering.fixImplement a ref on your custom input and explicitly call `focus()` on the input's ref within the `onSelect` handler, potentially after updating the state. Pass the ref correctly to the underlying input element. -
The `selected` prop doesn't seem to update the calendar or change the selected date.
cause Starting from v9, `selected` became a controlled prop. If `selected` is provided, `onSelect` must also be provided to handle state updates.fixWhen using the `selected` prop, always pair it with an `onSelect` prop to manage the state. For example: `const [selected, setSelected] = useState<Date>(); return <DayPicker selected={selected} onSelect={setSelected} />`.
Warnings
- breaking The default grid markup and class names for UI elements changed in v9.11.3, potentially affecting brittle snapshot tests or custom CSS rules that relied on the previous structure. For example, `day_disabled` is now `disabled`, `cell` is now `day`, and `day` is `day_button`.
- gotcha Since v9.12.0, built-in locales (e.g., `es`, `enUS`) now ship with translated labels for elements like 'Go to next month' or 'Today'. If you were previously providing these translations via the `labels` prop, you might find redundant labels or unexpected behavior.
- breaking The `DayPickerInput` component has been entirely removed in v8. Upgrading from v7 or earlier requires a complete rewrite of any input-field integrations, typically by using a controlled `DayPicker` component in conjunction with a custom input field.
- breaking Many prop names were changed in v8 (e.g., `showWeekNumbers` to `showWeekNumber`, `initialMonth` to `defaultMonth`, `selectedDays` to `selected`, `disabledDays` to `disabled`). If upgrading from v7, these changes will break existing implementations.
- breaking The `date-fns` library became a peer dependency starting from v8. While `react-day-picker` previously relied on it internally, it's now explicitly required for proper functioning, and users need to install it alongside the package.
- gotcha When using `DayPicker` in range selection mode and a full range is already selected, subsequent clicks would typically extend the existing range. The `resetOnSelect` prop was introduced in v9.14.0 to change this behavior and start a new range.
Install
-
npm install react-day-picker -
yarn add react-day-picker -
pnpm add react-day-picker
Imports
- DayPicker
const DayPicker = require('react-day-picker');import { DayPicker } from 'react-day-picker'; - styles
import 'react-day-picker/lib/style.css';
import 'react-day-picker/dist/style.css';
- es (locale)
import { es } from 'react-day-picker';import { es } from 'react-day-picker/locale'; - DayPicker (Hijri calendar)
import { DayPicker } from 'react-day-picker/hijri';
Quickstart
import React, { useState } from 'react';
import { DayPicker } from 'react-day-picker';
import { enUS } from 'react-day-picker/locale';
import 'react-day-picker/dist/style.css';
interface MyDatePickerProps {
initialDate?: Date;
}
export function MyDatePicker({ initialDate }: MyDatePickerProps) {
const [selectedDate, setSelectedDate] = useState<Date | undefined>(initialDate);
const handleDaySelect = (date: Date | undefined) => {
setSelectedDate(date);
};
return (
<div className="my-day-picker-container">
<h3>Select a Date</h3>
<DayPicker
mode="single"
selected={selectedDate}
onSelect={handleDaySelect}
locale={enUS}
captionLayout="dropdown"
fromYear={2000}
toYear={2030}
footer={
selectedDate
? `<p>You selected ${selectedDate.toLocaleDateString()}</p>`
: '<p>Please pick a day.</p>'
}
/>
<style jsx global>{`
.my-day-picker-container {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol';
max-width: 300px;
margin: 20px auto;
padding: 15px;
border: 1px solid #e0e0e0;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.my-day-picker-container h3 {
text-align: center;
margin-bottom: 20px;
color: #333;
}
.my-day-picker-container p {
text-align: center;
color: #555;
margin-top: 15px;
font-size: 0.9em;
}
.rdp {
--rdp-cell-size: 36px;
--rdp-background-color: #f7f7f7;
--rdp-accent-color: #007bff;
--rdp-selected-color: #fff;
--rdp-today-color: #007bff;
--rdp-caption-color: #333;
--rdp-nav-button-color: #666;
--rdp-border-radius: 4px;
}
`}</style>
</div>
);
}