React Nice Dates

A responsive, touch-friendly, and modular date picker library.

Overview

React Nice Dates is composed of a set of components and utilities with different levels of abstraction that you can use to build your own date pickers.

At the top level, you have DatePicker and DateRangePicker. These are slightly-opinionated components that should cover the most common use-cases. They allow displaying date inputs with a calendar popover below. They make no assumptions about how your inputs should look. Instead, they provide all the necessary props so you can render them yourself.

Here’s the most basic example using the DatePicker component:

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { enGB } from 'date-fns/locale'
import { DatePicker } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
function DatePickerExample() {
const [date, setDate] = useState()
return (
<DatePicker date={date} onDateChange={setDate} locale={enGB}>
{({ inputProps, focused }) => (
<input
className={'input' + (focused ? ' -focused' : '')}
{...inputProps}
/>
)}
</DatePicker>
)
}

Hint: If you are using a touch device, you can also change the current month by dragging the calendar grid up or down.

Here’s a more complete example, this time using the DateRangePicker component:

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { enGB } from 'date-fns/locale'
import { DateRangePicker, START_DATE, END_DATE } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
function DateRangePickerExample() {
const [startDate, setStartDate] = useState()
const [endDate, setEndDate] = useState()
return (
<DateRangePicker
startDate={startDate}
endDate={endDate}
onStartDateChange={setStartDate}
onEndDateChange={setEndDate}
minimumDate={new Date()}
format='dd MMM yyyy'
locale={enGB}
>
{({ startDateInputProps, endDateInputProps, focus }) => (
<div className='date-range'>
<input
className={'input' + (focus === START_DATE ? ' -focused' : '')}
{...startDateInputProps}
placeholder='Start date'
/>
<span className='date-range_arrow' />
<input
className={'input' + (focus === END_DATE ? ' -focused' : '')}
{...endDateInputProps}
placeholder='End date'
/>
</div>
)}
</DateRangePicker>
)
}

Customizing how the calendar appears

Next, you have DatePickerCalendar and DateRangePickerCalendar, the calendar-only date picker components (used by DatePicker and DateRangePicker). Use these if you want to display the calendars inline or implement your own popover component, for example.

DatePickerCalendar example:

Selected date: none.

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { format } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { DatePickerCalendar } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
function DatePickerCalendarExample() {
const [date, setDate] = useState()
return (
<div>
<p>
Selected date: {date ? format(date, 'dd MMM yyyy', { locale: enGB }) : 'none'}.
</p>
<DatePickerCalendar date={date} onDateChange={setDate} locale={enGB} />
</div>
)
}

DateRangePickerCalendar example:

Selected start date: none.

Selected end date: none.

Currently selecting: startDate.

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { format } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { DateRangePickerCalendar, START_DATE } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
export default function DateRangePickerCalendarExample() {
const [startDate, setStartDate] = useState()
const [endDate, setEndDate] = useState()
const [focus, setFocus] = useState(START_DATE)
const handleFocusChange = newFocus => {
setFocus(newFocus || START_DATE)
}
return (
<div>
<p>Selected start date: {startDate ? format(startDate, 'dd MMM yyyy', { locale: enGB }) : 'none'}.</p>
<p>Selected end date: {endDate ? format(endDate, 'dd MMM yyyy', { locale: enGB }) : 'none'}.</p>
<p>Currently selecting: {focus}.</p>
<DateRangePickerCalendar
startDate={startDate}
endDate={endDate}
focus={focus}
onStartDateChange={setStartDate}
onEndDateChange={setEndDate}
onFocusChange={handleFocusChange}
locale={enGB}
/>
</div>
)
}

Customizing days

Modifiers define what CSS classes are applied to each calendar day. All the components accept a modifiersprop—an object where each key corresponds to the modifier name, and each value corresponds to a function that receives a date parameter and must return a boolean determining whether that modifier class should apply to that particular day.

The default modifiers are disabled, selected, and today. You can also create your own modifiers by passing a modifiersClassNames which will be matched to the modifiers object.

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { getDay } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { DatePickerCalendar } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
const modifiers = {
disabled: date => getDay(date) === 6, // Disables Saturdays
highlight: date => getDay(date) === 2 // Highlights Tuesdays
}
const modifiersClassNames = {
highlight: '-highlight'
}
export default function ModifiersExample() {
const [date, setDate] = useState()
return (
<DatePickerCalendar
date={date}
onDateChange={setDate}
locale={enGB}
modifiers={modifiers}
modifiersClassNames={modifiersClassNames}
/>
)
}
// In your CSS:
// .nice-dates-day.-highlight { color: orange; }

Implementing your own date-picking behavior

If you need to implement a date-picking behavior not covered by the previous components, you can use the Calendar component directly (DatePickerCalendar andDateRangePickerCalendar are themselves wrappers around this component). It accepts callbacks for when a day is clicked or hovered, which you can then use to create modifiers to control which days are selected.

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { isSameDay } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { Calendar } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
// Very rough implementation of multiple date selection
export default function CalendarExample() {
const [selectedDates, setSelectedDates] = useState([])
const modifiers = {
selected: date => selectedDates.some(selectedDate => isSameDay(selectedDate, date))
}
const handleDayClick = date => {
setSelectedDates([...selectedDates, date])
}
return (
<Calendar onDayClick={handleDayClick} modifiers={modifiers} locale={enGB} />
)
}

Parsing text inputs

You can also use the useDateInput hook if you want to have the same date-parsing functionality on text inputs in your custom implementation.

Here’s an example using it on a standalone input:

The selected date is

import React, { useState } from 'react'
import { format } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { useDateInput } from 'react-nice-dates'
export default function StandaloneInputExample() {
const [date, setDate] = useState()
const inputProps = useDateInput({
date,
format: 'yyyy-MM-dd',
locale: enGB,
onDateChange: setDate
})
const handleReset = () => {
setDate(new Date())
}
return (
<div>
<p>The selected date is {date && format(date, 'dd MMM yyyy', { locale: enGB })}</p>
<button onClick={handleReset}>Set today</button>
<input className='input' {...inputProps} />
</div>
)
}

And here it is paired with DatePickerCalendar:

The selected date is

February
MonTueWedThuFriSatSun
2728293031Feb1234567891011121314151617181920212223242526272829Mar12345678
import React, { useState } from 'react'
import { format } from 'date-fns'
import { enGB } from 'date-fns/locale'
import { DatePickerCalendar, useDateInput } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
export default function DatePickerCalendarWithInputExample() {
const [date, setDate] = useState()
const inputProps = useDateInput({
date,
format: 'yyyy-MM-dd',
locale: enGB,
onDateChange: setDate
})
return (
<div>
<p>The selected date is {date && format(date, 'dd MMM yyyy', { locale: enGB })}</p>
<input className='input' {...inputProps} />
<DatePickerCalendar date={date} onDateChange={setDate} locale={enGB} />
</div>
)
}

Localization

As you might have noticed, React Nice Dates relies of the awesome date-fns library as a peer dependency. All components require a locale prop, which must be a date-fns locale object of your desired language.

US English:

February
SunMonTueWedThuFriSat
262728293031Feb1234567891011121314151617181920212223242526272829Mar1234567

Spanish:

febrero
lunmarmiéjueviesabdom
2728293031feb1234567891011121314151617181920212223242526272829mar12345678
import React, { useState } from 'react'
import { enUS, es } from 'date-fns/locale'
import { DatePicker } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
export default function LocalesExample() {
const [date, setDate] = useState()
return (
<div>
<p>US English:</p>
<DatePicker date={date} onDateChange={setDate} locale={enUS}>
{({ inputProps, focused }) => (
<input className={'input' + (focused ? ' -focused' : '')} {...inputProps} />
)}
</DatePicker>
<p>Spanish:</p>
<DatePicker date={date} onDateChange={setDate} locale={es} format='dd/MM/yyyy'>
{({ inputProps, focused }) => (
<input className={'input' + (focused ? ' -focused' : '')} {...inputProps} placeholder='DD/MM/YYYY' />
)}
</DatePicker>
</div>
)
}

Installation

1. Add the react-nice-dates and date-fns packages to your dependencies.

With NPM:

npm install react-nice-dates date-fns --save

Or with Yarn:

yarn add react-nice-dates date-fns

2. Import the desired components, a date-fns locale object of your language, and the CSS:

import { enGB } from 'date-fns/locale'
import { DatePickerCalendar } from 'react-nice-dates'
import 'react-nice-dates/build/style.css'
//...
<DatePickerCalendar locale={enGB} />

Style customization

You can use and override the compiled CSS on your project:

.nice-dates-navigation, .nice-dates-day {
color: #111;
}
.nice-dates-popover {
box-shadow: none;
border: 1px solid #ddd;
border-radius: 2px;
max-width: 480px;
transition: none;
}

Or, if you’re using SASS, import the original SASS file for easier customization:

// Existing variables and their defaults
$nice-dates-color-gray-dark: #333;
$nice-dates-color-gray: #999;
$nice-dates-color-gray-light: #ddd;
$nice-dates-color-accent: $nice-dates-color-gray-dark;
$nice-dates-font-size-small: 12px;
$nice-dates-font-size-base: 14px;
$nice-dates-font-size-big: 16px;
@import 'react-nice-dates/src/style.scss';
// Other overrides...

API Reference

DatePicker props

children: func.isRequired, // ({ inputProps, focused }) => {}
locale: object.isRequired,
date: instanceOf(Date),
onDateChange: func,
format: string, // Default: locale.formatLong.date({ width: 'short' })
minimumDate: instanceOf(Date), // See Calendar props
maximumDate: instanceOf(Date), // See Calendar props
modifiers: objectOf(func),
modifiersClassNames: objectOf(string)

inputProps properties:

onBlur,
onChange,
onFocus,
placeholder, // Default: format.toLowerCase()
readOnly, // Default: true for touch devices to avoid triggering the on-screen keyboard
ref,
type, // Default: 'text'
value

DateRangePicker props

children: func.isRequired, // ({ startDateInputProps, endDateInputProps, focus }) => {}
locale: object.isRequired,
startDate: instanceOf(Date),
endDate: instanceOf(Date),
onStartDateChange: func,
onEndDateChange: func,
format: string, // Default: locale.formatLong.date({ width: 'short' })
minimumDate: instanceOf(Date), // See Calendar props
maximumDate: instanceOf(Date), // See Calendar props
modifiers: objectOf(func),
modifiersClassNames: objectOf(string)

startDateInputProps and endDateInputProps properties:

onBlur,
onChange,
onFocus,
placeholder, // Default: format.toLowerCase()
readOnly, // Default: true for touch devices to avoid triggering the on-screen keyboard
ref,
type, // Default: 'text'
value

DatePickerCalendar props

locale: object.isRequired,
date: instanceOf(Date),
month: instanceOf(Date), // See Calendar props
onDateChange: func,
onMonthChange: func, // See Calendar props
minimumDate: instanceOf(Date), // See Calendar props
maximumDate: instanceOf(Date), // See Calendar props
modifiers: objectOf(func),
modifiersClassNames: objectOf(string)

DateRangePickerCalendar props

locale: object.isRequired,
startDate: instanceOf(Date),
endDate: instanceOf(Date),
focus: oneOf([START_DATE, END_DATE]),
month: instanceOf(Date), // See Calendar props
onStartDateChange: func.isRequired,
onEndDateChange: func.isRequired,
onFocusChange: func.isRequired,
onMonthChange: func, // See Calendar props
minimumDate: instanceOf(Date), // See Calendar props
maximumDate: instanceOf(Date), // See Calendar props
modifiers: objectOf(func),
modifiersClassNames: objectOf(string)

Calendar props

locale: object.isRequired,
minimumDate: instanceOf(Date), // Days before minimumDate will be disabled
maximumDate: instanceOf(Date), // Days after maximumDate will be disabled
modifiers: objectOf(func),
modifiersClassNames: objectOf(string),
month: instanceOf(Date), // Optional: Turns current month into a controlled prop
onMonthChange: func, // Optional: Turns current month into a controlled prop
onDayHover: func,
onDayClick: func

useDateInput

const {
onBlur
onChange
onFocus
placeholder // Default: format.toLowerCase(),
type // 'text'
value
} = useDateInput({
date, // Current date
format, // Default: locale.formatLong.date({ width: 'short' })
locale, // date-fns locale object
minimumDate, // Dates before minimumDate won’t be valid
maximumDate, // Dates after maximumDate won’t be valid
onDateChange, // Function to call when a valid date is typed
validate // Custom date validation function. Recieves a date and must return a boolean.
})