An easily internationalizable, accessible, mobile-friendly datepicker library for the web.
For examples of the datepicker in action, go to http://airbnb.io/react-dates.
OR
To run that demo on your own computer:
- Clone this repository
npm install
npm run storybook
- Visit http://localhost:6006/
Ensure packages are installed with correct version numbers by running:
(
export PKG=react-dates;
npm info "$PKG" peerDependencies --json | command sed 's/[\{\},]//g ; s/: /@/g; s/ *//g' | xargs npm install --save "$PKG"
)
Which produces and runs a command like:
npm install --save react-dates moment@>=#.## react@>=#.## react-dom@>=#.##
import 'react-dates/initialize';
As of v13.0.0 of react-dates
, this project relies on react-with-styles
. If you want to continue using CSS stylesheets and classes, there is a little bit of extra set-up required to get things going. As such, you need to import react-dates/initialize
to set up class names on our components. This import should go at the top of your application as you won't be able to import any react-dates
components without it.
Note: This component assumes box-sizing: border-box
is set globally in your page's CSS.
import { DateRangePicker, SingleDatePicker, DayPickerRangeController } from 'react-dates';
Using Webpack with CSS loader, add the following import to your app:
import 'react-dates/lib/css/_datepicker.css';
Create a CSS file with the contents of require.resolve('react-dates/lib/css/_datepicker.css')
and include it in your html <head>
section.
To see this in action, you can check out https://github.com/majapw/react-dates-demo which adds react-dates
on top of a simple create-react-app
setup.
Right now, the easiest way to tweak react-dates
to your heart's content is to create another stylesheet to override the default react-dates styles. For example, you could create a file named react_dates_overrides.css
with the following contents:
.CalendarDay__highlighted_calendar {
background: #82E0AA;
color: #186A3B;
}
.CalendarDay__highlighted_calendar:hover {
background: #58D68D;
color: #186A3B;
}
.CalendarDay__highlighted_calendar:active {
background: #58D68D;
color: #186A3B;
}
This would override the background and text colors applied to highlighted calendar days. You can use this method with the default set-up to override any aspect of the calendar to have it better fit to your particular needs.
We provide a handful of components for your use. If you supply essential props to each component, you'll get a full featured interactive date picker. With additional optional props, you can customize the look and feel of the inputs, calendar, etc. You can see what each of the props do in the live demo or explore how to properly wrap the pickers in the examples folder.
The DateRangePicker
is a fully controlled component that allows users to select a date range. You can control the selected
dates using the startDate
, endDate
, and onDatesChange
props as shown below. The DateRangePicker
also manages internal
state for partial dates entered by typing (although onDatesChange
will not trigger until a date has been entered
completely in that case). Similarly, you can control which input is focused as well as calendar visibility (the calendar is
only visible if focusedInput
is defined) with the focusedInput
and onFocusChange
props as shown below.
Here is the minimum REQUIRED setup you need to get the DateRangePicker
working:
<DateRangePicker
startDate={this.state.startDate} // momentPropTypes.momentObj or null,
startDateId="your_unique_start_date_id" // PropTypes.string.isRequired,
endDate={this.state.endDate} // momentPropTypes.momentObj or null,
endDateId="your_unique_end_date_id" // PropTypes.string.isRequired,
onDatesChange={({ startDate, endDate }) => this.setState({ startDate, endDate })} // PropTypes.func.isRequired,
focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
/>
The following is a list of other OPTIONAL props you may provide to the DateRangePicker
to customize appearance and behavior to your heart's desire. Again, please explore the storybook for more information on what each of these props do.
// input related props
startDatePlaceholderText: PropTypes.string,
endDatePlaceholderText: PropTypes.string,
disabled: PropTypes.bool,
required: PropTypes.bool,
readOnly: PropTypes.bool,
screenReaderInputMessage: PropTypes.string,
showClearDates: PropTypes.bool,
showDefaultInputIcon: PropTypes.bool,
customInputIcon: PropTypes.node,
customArrowIcon: PropTypes.node,
customCloseIcon: PropTypes.node,
noBorder: PropTypes.bool,
block: PropTypes.bool,
small: PropTypes.bool,
regular: PropTypes.bool,
// calendar presentation and interaction related props
renderMonth: PropTypes.func,
orientation: OrientationShape,
anchorDirection: anchorDirectionShape,
horizontalMargin: PropTypes.number,
withPortal: PropTypes.bool,
withFullScreenPortal: PropTypes.bool,
daySize: nonNegativeInteger,
isRTL: PropTypes.bool,
initialVisibleMonth: PropTypes.func,
firstDayOfWeek: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6]),
numberOfMonths: PropTypes.number,
keepOpenOnDateSelect: PropTypes.bool,
reopenPickerOnClearDates: PropTypes.bool,
renderCalendarInfo: PropTypes.func,
hideKeyboardShortcutsPanel: PropTypes.bool,
// navigation related props
navPrev: PropTypes.node,
navNext: PropTypes.node,
onPrevMonthClick: PropTypes.func,
onNextMonthClick: PropTypes.func,
onClose: PropTypes.func,
transitionDuration: nonNegativeInteger, // milliseconds
// day presentation and interaction related props
renderCalendarDay: PropTypes.func,
renderDayContents: PropTypes.func,
minimumNights: PropTypes.number,
enableOutsideDays: PropTypes.bool,
isDayBlocked: PropTypes.func,
isOutsideRange: PropTypes.func,
isDayHighlighted: PropTypes.func,
// internationalization props
displayFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
monthFormat: PropTypes.string,
weekDayFormat: PropTypes.string,
phrases: PropTypes.shape(getPhrasePropTypes(DateRangePickerPhrases)),
The SingleDatePicker
is a fully controlled component that allows users to select a single date. You can control the selected
date using the date
and onDateChange
props as shown below. The SingleDatePicker
also manages internal
state for partial dates entered by typing (although onDateChange
will not trigger until a date has been entered
completely in that case). Similarly, you can control whether or not the input is focused (calendar visibility is also
controlled with the same props) with the focused
and onFocusChange
props as shown below.
Here is the minimum REQUIRED setup you need to get the SingleDatePicker
working:
<SingleDatePicker
date={this.state.date} // momentPropTypes.momentObj or null
onDateChange={date => this.setState({ date })} // PropTypes.func.isRequired
focused={this.state.focused} // PropTypes.bool
onFocusChange={({ focused }) => this.setState({ focused })} // PropTypes.func.isRequired
/>
The following is a list of other OPTIONAL props you may provide to the SingleDatePicker
to customize appearance and behavior to your heart's desire. Again, please explore the storybook for more information on what each of these props do.
// input related props
id: PropTypes.string.isRequired,
placeholder: PropTypes.string,
disabled: PropTypes.bool,
required: PropTypes.bool,
readOnly: PropTypes.bool,
screenReaderInputMessage: PropTypes.string,
showClearDate: PropTypes.bool,
customCloseIcon: PropTypes.node,
showDefaultInputIcon: PropTypes.bool,
customInputIcon: PropTypes.node,
noBorder: PropTypes.bool,
block: PropTypes.bool,
small: PropTypes.bool,
regular: PropTypes.bool,
// calendar presentation and interaction related props
renderMonth: PropTypes.func,
orientation: OrientationShape,
anchorDirection: anchorDirectionShape,
horizontalMargin: PropTypes.number,
withPortal: PropTypes.bool,
withFullScreenPortal: PropTypes.bool,
initialVisibleMonth: PropTypes.func,
firstDayOfWeek: PropTypes.oneOf([0, 1, 2, 3, 4, 5, 6]),
numberOfMonths: PropTypes.number,
keepOpenOnDateSelect: PropTypes.bool,
reopenPickerOnClearDate: PropTypes.bool,
renderCalendarInfo: PropTypes.func,
hideKeyboardShortcutsPanel: PropTypes.bool,
daySize: nonNegativeInteger,
isRTL: PropTypes.bool,
// navigation related props
navPrev: PropTypes.node,
navNext: PropTypes.node,
onPrevMonthClick: PropTypes.func,
onNextMonthClick: PropTypes.func,
onClose: PropTypes.func,
transitionDuration: nonNegativeInteger, // milliseconds
// day presentation and interaction related props
renderCalendarDay: PropTypes.func,
renderDayContents: PropTypes.func,
enableOutsideDays: PropTypes.bool,
isDayBlocked: PropTypes.func,
isOutsideRange: PropTypes.func,
isDayHighlighted: PropTypes.func,
// internationalization props
displayFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
monthFormat: PropTypes.string,
weekDayFormat: PropTypes.string,
phrases: PropTypes.shape(getPhrasePropTypes(SingleDatePickerPhrases)),
The DayPickerRangeController
is a calendar-only version of the DateRangePicker
. There are no inputs (which also means
that currently, it is not keyboard accessible) and the calendar is always visible, but you can select a date range much in the same way you would with the DateRangePicker
. You can control the selected
dates using the startDate
, endDate
, and onDatesChange
props as shown below. Similarly, you can control which input is focused with the focusedInput
and onFocusChange
props as shown below. The user will only be able to select a date if focusedInput
is provided.
Here is the minimum REQUIRED setup you need to get the DayPickerRangeController
working:
<DayPickerRangeController
startDate={this.state.startDate} // momentPropTypes.momentObj or null,
endDate={this.state.endDate} // momentPropTypes.momentObj or null,
onDatesChange={({ startDate, endDate }) => this.setState({ startDate, endDate })} // PropTypes.func.isRequired,
focusedInput={this.state.focusedInput} // PropTypes.oneOf([START_DATE, END_DATE]) or null,
onFocusChange={focusedInput => this.setState({ focusedInput })} // PropTypes.func.isRequired,
/>
The following is a list of other OPTIONAL props you may provide to the DayPickerRangeController
to customize appearance and behavior to your heart's desire. Again, please explore the storybook for more information on what each of these props do.
// calendar presentation and interaction related props
enableOutsideDays: PropTypes.bool,
numberOfMonths: PropTypes.number,
orientation: ScrollableOrientationShape,
withPortal: PropTypes.bool,
initialVisibleMonth: PropTypes.func,
renderCalendarInfo: PropTypes.func,
onOutsideClick: PropTypes.func,
keepOpenOnDateSelect: PropTypes.bool,
noBorder: PropTypes.bool,
// navigation related props
navPrev: PropTypes.node,
navNext: PropTypes.node,
onPrevMonthClick: PropTypes.func,
onNextMonthClick: PropTypes.func,
transitionDuration: nonNegativeInteger, // milliseconds
// day presentation and interaction related props
renderCalendarDay: PropTypes.func,
renderDayContents: PropTypes.func,
minimumNights: PropTypes.number,
isOutsideRange: PropTypes.func,
isDayBlocked: PropTypes.func,
isDayHighlighted: PropTypes.func,
// internationalization props
monthFormat: PropTypes.string,
weekDayFormat: PropTypes.string,
phrases: PropTypes.shape(getPhrasePropTypes(DayPickerPhrases)),
/>
Moment.js is a peer dependency of react-dates
, so react-dates
will use a single instance of moment
which is imported in the user's project. To load a locale it is enough to invoke moment.locale
in the component where moment
is imported, with the locale key of choice, e.g.:
moment.locale('pl'); // Polish
react-dates
no longer relies strictly on CSS, but rather relies on react-with-styles
as an abstraction layer between how styles are applied and how they are written. The instructions above will get the project working out of the box, but there's a lot more customization that can be done.
The react-dates/initialize
script actually relies on react-with-styles-interface-css under the hood. If you are interested in a different solution for styling in your project, you can do your own initialization of a another interface. At Airbnb, for instance, we rely on Aphrodite under the hood and therefore use the Aphrodite interface for react-with-styles
. If you want to do the same, you would use the following pattern:
import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';
import aphroditeInterface from 'react-with-styles-interface-aphrodite';
import DefaultTheme from 'react-dates/lib/theme/DefaultTheme';
ThemedStyleSheet.registerInterface(aphroditeInterface);
ThemedStyleSheet.registerTheme(DefaultTheme);
The above code has to be run before any react-dates
component is imported. Otherwise, you will get an error. Also note that if you register any custom interface manually, you must also manually register a theme.
react-dates
also now supports a different way to theme. You can see the default theme values in this file and you would override them in the following manner:
import ThemedStyleSheet from 'react-with-styles/lib/ThemedStyleSheet';
import aphroditeInterface from 'react-with-styles-interface-aphrodite';
import DefaultTheme from 'react-dates/lib/theme/DefaultTheme';
ThemedStyleSheet.registerInterface(aphroditeInterface);
ThemedStyleSheet.registerTheme({
reactDates: {
...DefaultTheme.reactDates,
color: {
...DefaultTheme.reactDates.color,
highlighted: {
backgroundColor: '#82E0AA',
backgroundColor_active: '#58D68D',
backgroundColor_hover: '#58D68D',
color: '#186A3B',
color_active: '#186A3B',
color_hover: '#186A3B',
},
},
},
});
The above code would use shades of green instead of shades of yellow for the highlight color on CalendarDay
components. Note that you must register an interface if you manually register a theme. One will not work without the other.
The default interface that react-dates
ships with is the CSS interface. If you want to use this interface along with the theme registration method, you will need to rebuild the core _datepicker.css
file. We do not currently expose a utility method to build this file, but you can follow along with the code in https://github.com/airbnb/react-dates/blob/master/scripts/buildCSS.js to build your own custom themed CSS file.