Mastering react-datepicker: A comprehensive guide for developers

Allie Beazell
Allie Beazell
Retool

Aug 4, 2020

Nobody likes working with dates (especially in Javascript), but unfortunately it's inevitable. If your app requires a date picker component (think: users select a date from a calendar), HackerOne has you covered with the react-datepicker library. This guide will walk through react-datepicker basics with a focus on building internal tools.

By the end of this article, you’ll know how to:

  • Import and use react-datepicker in your React app to build a simple datepicker
  • Customize your datepicker with time functionality, disabling dates, and a clear button

If you just want to grab the code and go, check out the tl;dr at the end of the article.

One note before we start: this article has been updated for 2024 but was originally published in 2020.

react-datepicker: What is it and why is it useful?

react-datepicker is a React library that is used by more than 237K developers with almost 8K stars on GitHub. The simple version of the datepicker component is incredibly easy to use and comes with some useful features like:

  • Localization
  • Accessibility
  • Advanced customization
  • Range support

Because it uses date-fns instead of moment, the entire library comes out to 437kB. It runs on the latest versions of Chrome, Firefox, and IE10+.

In this tutorial, we'll build an internal tool for a customer support team. Let’s say that we’ve already built a table that displays order data using react-table—that's a great first step! But to make this tool truly useful, customer support reps need to be able to filter their view to a specific set of dates. That's where datepicker comes in.

The customer support rep needs to be able to:

  • Open a calendar view when the datepicker is clicked
  • Select a range of date values and times
  • Not select future dates
  • Clear the datepicker by clicking the “X” button

In other words, here's how the final product should look and feel:

  • With Retool, you can build applications with 50+ drag-and-drop components including a datepicker.

How to build a datepicker for an internal tool using react-datepicker

Stand up a simple datepicker

If you're just here for the code, go ahead and jump to the TL;DR syntax summary.

Let’s keep things simple to start off: we’ll create one datepicker that only allows the user to select a single date field—no other bells and whistles.

We'll leverage the useState() hook in our function. If you’re not familiar with React Hooks, we recommend checking out React’s Hooks docs before starting this tutorial.

There are three simple steps for creating a datepicker:

  • Import the datepicker component from react-datepicker and react-datepicker.css for styling.
  • Set an initial date in the state (using the useState() Hook).
  • Render the datepicker, telling onChange to update the date in state using the setDate() function.
1import React, { useState } from "react";
2
3import DatePicker from "react-datepicker";
4import "react-datepicker/dist/react-datepicker.css";
5
6export default function TableDatePicker() {
7 const [date, setDate] = useState(new Date());
8
9 return <DatePicker selected={date} onChange={(date) => setDate(date)} />;
10}

And, voila, you have a datepicker that starts on today’s date and will open a calendar to select a new date when clicked!

Create a datepicker range

The first feature we are going to add is the ability to set a date range on our datepicker. We want our customer support reps to be able to narrow down orders that happened between a specific set of dates.

react-datepicker doesn’t have native support for ranges, but we can get around it by doubling the datepicker component: one for the start date and one for the end date. Now that we already have our first datepicker, we simply need to adjust it to specifically handle a start date:

1export default function TableDatePicker() {
2 const [startDate, setStartDate] = useState(new Date());
3
4 return (
5   <DatePicker
6     selected={startDate}
7     onChange={date => setStartDate(date)}
8     selectsStart // tells this DatePicker that it is part of a range*
9     startDate={startDate}
10   />
11 );
12}
13

Then, we'll create a second datepicker that can handle the end date. Note that the endDate datepicker needs a minDate to be set. Since we’re picking a range, we can’t have the endDate be earlier than the startDate (time doesn’t work like that!).

1export default function TableDatePicker() {
2 const [startDate, setStartDate] = useState(new Date());
3 const [endDate, setEndDate] = useState(new Date());
4
5 return (
6   <div> // don't forget to wrap your DatePickers
7     <DatePicker
8       selected={startDate}
9       selectsStart
10       startDate={startDate}
11       endDate={endDate} // add the endDate to your startDate DatePicker now that it is defined
12       onChange={date => setStartDate(date)}
13     />
14    <DatePicker
15       selected={endDate}
16       selectsEnd
17       startDate={startDate}
18       endDate={endDate}
19       minDate={startDate}
20       onChange={date => setEndDate(date)}
21     />
22   </div>
23 );
24}
25

And that’s it! The final version of the code all put together will look like this:

1import React, { useState } from "react";
2
3import DatePicker from "react-datepicker";
4import "react-datepicker/dist/react-datepicker.css";
5
6export default function TableDatePicker() {
7 const [startDate, setStartDate] = useState(new Date());
8 const [endDate, setEndDate] = useState(new Date());
9
10 return (
11   <div>
12     <DatePicker
13       selected={startDate}
14       selectsStart
15       startDate={startDate}
16       endDate={endDate}
17       onChange={date => setStartDate(date)}
18     />
19     <DatePicker
20       selected={endDate}
21       selectsEnd
22       startDate={startDate}
23       endDate={endDate}
24       minDate={startDate}
25       onChange={date => setEndDate(date)}
26     />
27   </div>
28 );
29}
30

Now we have two datepickers that the customer support reps can use to select their ranges. Plus, the react-datepicker library already handles highlighting the selected dates for us.

Add time granularity

Let’s assume that our example company has thousands of rows of data, filled with row after row of customer order data. Even if reps only select a couple days, they’ll still get flooded with a ton of data. To make life easier for them, let’s add a time option to the datepicker so that reps can filter things down to an even more granular level.

react-datepicker comes with two options for adding time to the calendar view:

While the input version can be very useful since it lets the user type in any time they want, we’re going to go with the select version because we’re okay with only letting our customer support reps choose times in half-hour increments.

To add the time selector to our datepickers, we’ll first add showTimeSelect to our datepicker component to let it know we want to display the time selector, and then we’ll format the date that’s displayed in the datepicker window so that it shows time too.

1const [startDate, setStartDate] = useState(null);
2const [endDate, setEndDate] = useState(null);
3
4return (
5 <>
6   <DatePicker
7     showTimeSelect
8     dateFormat="MMMM d, yyyy h:mmaa"
9     selected={startDate}
10     selectsStart
11     startDate={startDate}
12     endDate={endDate}
13     onChange={(date) => setStartDate(date)}
14   />
15   <DatePicker
16     showTimeSelect
17     dateFormat="MMMM d, yyyy h:mmaa"
18     selected={endDate}
19     selectsEnd
20     startDate={startDate}
21     endDate={endDate}
22     minDate={startDate}
23     onChange={(date) => setEndDate(date)}
24   />
25 </>
26);

Hey, that took almost no time at all (sorry).

Extend your datepicker with more features

We've just barely scratched the surface of what react-datepicker can do. A few useful ones:

Add a placeholder prompt to the datepicker

Instead of having the datepicker start on today’s date, why don’t we prompt the user to enter a start and end date so that our range datepicker is a little more clear? To do this, we need to add a placeholderText field and change the initial startDate and endDate values to null.

1export default function TableDatePicker() {
2 const [startDate, setStartDate] = useState(null);
3 const [endDate, setEndDate] = useState(null);
4
5 return (
6   <div>
7     <DatePicker
8       placeholderText="Select Start Date"
9       showTimeSelect
10       dateFormat="MMMM d, yyyy h:mmaa"
11       selected={startDate}
12       selectsStart
13       startDate={startDate}
14       endDate={endDate}
15       onChange={(date) => setStartDate(date)}
16     />
17     <DatePicker
18       placeholderText="Select End Date"
19       showTimeSelect
20       dateFormat="MMMM d, yyyy h:mmaa"
21       selected={endDate}
22       selectsEnd
23       startDate={startDate}
24       endDate={endDate}
25       minDate={startDate}
26       onChange={(date) => setEndDate(date)}
27     />
28   </div>
29 );
30}
31
32

Now, the user can easily choose a start and end date and time in a logical order.

Disable future dates

Since our reps are dealing with orders from customers, all of the data in the table they are viewing will be in the past. If they were to select a date in the future, there would be no data to view, and the rep would be looking at an empty table. Instead of that happening, lets disable all future dates in the calendar so that the rep can’t select them.

For this feature, we’re going to add the filterDate field and define an arrow function that returns a Boolean value depending on whether the date displayed is in the future or not.

1<DatePicker
2filterDate={d => {
3  return new Date() > d;
4}}
5placeholderText="Select Start Date"
6showTimeSelect
7dateFormat="MMMM d, yyyy h:mmaa"
8selected={startDate}
9selectsStart
10startDate={startDate}
11endDate={endDate}
12onChange={date => setStartDate(date)}
13/>
14<DatePicker
15filterDate={d => {
16  return new Date() > d;
17}}
18placeholderText="Select End Date"
19showTimeSelect
20dateFormat="MMMM d, yyyy h:mmaa"
21selected={endDate}
22selectsEnd
23startDate={startDate}
24endDate={endDate}
25minDate={startDate}
26onChange={date => setEndDate(date)}
27/>
28
29

Great! Now the rep will only be able to filter the table based on dates that actually have order data, and we avoid time travel paradoxes.

Add a button to clear the datepicker

If the customer support rep decides that they no longer want to filter by date, we want to make it easy for them to clear the filter. Let’s give them a simple X they can press to clear the datepicker.

1<DatePicker
2 isClearable
3 filterDate={d => {
4   return new Date() > d;
5 }}
6 placeholderText="Select Start Date"
7 showTimeSelect
8 dateFormat="MMMM d, yyyy h:mmaa"
9 selected={startDate}
10 selectsStart
11 startDate={startDate}
12 endDate={endDate}
13 onChange={date => setStartDate(date)}
14/>
15<DatePicker
16 isClearable
17 filterDate={d => {
18   return new Date() > d;
19 }} 
20 placeholderText="Select End Date"
21 showTimeSelect
22 dateFormat="MMMM d, yyyy h:mmaa"
23 selected={endDate}
24 selectsEnd
25 startDate={startDate}
26 endDate={endDate}
27 minDate={startDate}
28 onChange={date => setEndDate(date)}
29/>
30

This one is just a simple Boolean prop type that is passed in to datepicker. Here is what the default clear button looks like:

At this point we should probably let you know that we added a little extra styling to make the datepicker look this way. If you choose to display the time in your datepicker, the clear button sits right on top of it, like this:

In order to expand the width of the datepicker boxes, we have to override some of the styling that we imported in react-datepicker.css. To do this, we are going to use Styled Components, a popular React library used for low-level styling.

First, import styled-components, and then define a new Styles component that will wrap around your datepicker. Then, move all of your datepicker code into a new function. You want your default function to export just your datepicker code (all wrapped up) with the <Styles> component around it.

Take careful note of the react-datepicker classnames that must be overwritten:

  • react-datepicker-wrapper
  • react-datepicker__input-container
  • react-datepicker__input-container input
1import React, { useState } from "react";
2import DatePicker from "react-datepicker";
3import "react-datepicker/dist/react-datepicker.css";
4import styled from "styled-components";
5
6const Styles = styled.div`
7 .react-datepicker-wrapper,
8 .react-datepicker__input-container,
9 .react-datepicker__input-container input {
10   width: 175px;
11 }
12`;
13
14export function DatePickerRange() {
15 const [startDate, setStartDate] = useState(null);
16 const [endDate, setEndDate] = useState(null);
17
18 return (
19   <div>
20     <DatePicker
21       isClearable
22       ...
23     />
24     <DatePicker
25       isClearable
26       ...
27     />
28   </div>
29 );
30}
31
32export default function TableDatePicker() {
33 return (
34   <Styles>
35     <DatePickerRange />
36   </Styles>
37 );
38}
39

And now that we’re overwriting classnames from react-datepicker, we might as well change up the style of our clear button. To override the button styles, you just need to change .react-datepicker__close-icon::before and .react-datepicker__close-icon::after.

1const Styles = styled.div`
2 .react-datepicker-wrapper,
3 .react-datepicker__input-container,
4 .react-datepicker__input-container input {
5   width: 175px;
6 }
7
8 .react-datepicker__close-icon::before,
9 .react-datepicker__close-icon::after {
10   background-color: red;
11 }
12`;
13

Here is our new, styled X button:

Extract data from the datepicker

Extracting the selected date(s) from your datepicker will depend on how your code is set up. For example, if I’m within the same component, getting the startDate and endDate is as simple as accessing the state.

1<div>
2<div style={{ display: "flex" }}>
3  <DatePicker ... />
4  <DatePicker ... />
5</div>
6<div>Selected start date={startDate ? startDate.toString() : null}</div>
7<div>Selected end date={endDate ? endDate.toString() : null}</div>
8</div>

Here you can see we are printing the selected date below the datepickers. Note that startDate and endDate are saved as Date objects so you must convert them to Strings with the toString() method before printing (or else your IDE will yell at you).

If you are working with multiple React components, then you will likely need to lift the state out of the datepicker components. That work goes a bit beyond the scope of this tutorial, but you can read up on how to do it in the React docs.

Pulling it all together: Your finished datepicker component with react-datepicker

You’ve now built an intuitive datepicker for your internal app! Here is our final datepicker:

Hopefully, this tutorial helped you understand how to create and customize a datepicker in React to suit your needs. We know we covered a lot of features here, so for good measure, here is the code for the datepicker we created, in its entirety:

1import React, { useState } from "react";
2
3import DatePicker from "react-datepicker";
4import "react-datepicker/dist/react-datepicker.css";
5import styled from "styled-components";
6
7const Styles = styled.div`
8.react-datepicker-wrapper,
9.react-datepicker__input-container,
10.react-datepicker__input-container input {
11  width: 175px;
12}
13
14.react-datepicker__close-icon::before,
15.react-datepicker__close-icon::after {
16  background-color: grey;
17}
18`;
19
20export function DatePickerRange() {
21 const [startDate, setStartDate] = useState(null);
22 const [endDate, setEndDate] = useState(null);
23
24 return (
25   <div style={{ display: "flex" }}>
26     <DatePicker
27       isClearable
28       filterDate={(d) => {
29         return new Date() > d;
30       }}
31       placeholderText="Select Start Date"
32       showTimeSelect
33       dateFormat="MMMM d, yyyy h:mmaa"
34       selected={startDate}
35       selectsStart
36       startDate={startDate}
37       endDate={endDate}
38       onChange={(date) => setStartDate(date)}
39     />
40     <DatePicker
41       isClearable
42       filterDate={(d) => {
43         return new Date() > d;
44       }}
45       placeholderText="Select End Date"
46       showTimeSelect
47       dateFormat="MMMM d, yyyy h:mmaa"
48       selected={endDate}
49       selectsEnd
50       startDate={startDate}
51       endDate={endDate}
52       minDate={startDate}
53       onChange={(date) => setEndDate(date)}
54     />
55   </div>
56 );
57}
58
59export default function TableDatePicker() {
60 return (
61   <Styles>
62     <DatePickerRange />
63   </Styles>
64 );
65}

For more code samples that cover every feature react-datepicker has to offer, check out React Datepicker’s website.

Retool also offers a complete set of powerful building blocks for building internal tools. Assemble your app in 30 seconds by dragging and dropping from more than 50 pre-built components. Start building today.

TL;DR: Syntax roundup

Create a simple datepicker

1import React, { useState } from "react";
2
3import DatePicker from "react-datepicker";
4import "react-datepicker/dist/react-datepicker.css";
5
6export default function TableDatePicker() {
7 const [date, setDate] = useState(new Date());
8
9 return <DatePicker selected={date} onChange={(date) => setDate(date)} />;
10}
11
12

Create a datepicker range

1export default function TableDatePicker() {
2 const [startDate, setStartDate] = useState(new Date());
3 const [endDate, setEndDate] = useState(new Date());
4
5 return (
6   <div>
7     <DatePicker
8       selected={startDate}
9       selectsStart
10       startDate={startDate}
11       endDate={endDate}
12       onChange={(date) => setStartDate(date)}
13     />
14     <DatePicker
15       selected={endDate}
16       selectsEnd
17       startDate={startDate}
18       endDate={endDate}
19       minDate={startDate}
20       onChange={(date) => setEndDate(date)}
21     />
22   </div>
23 );
24}
25
26

Selecting time with datepicker

1<DatePicker
2 showTimeSelect
3 dateFormat="MMMM d, yyyy h:mmaa"
4 selected={date}
5 onChange={(date) => setDate(date)}
6/>;

Add a placeholder

1export default function TableDatePicker() {
2 const [date, setDate] = useState(null);
3
4 return (
5   <DatePicker
6     placeholderText="Select Date"
7     selected={date}
8     onChange={(date) => setDate(date)}
9   />
10 );
11}

Disable future dates

1<DatePicker
2 filterDate={(d) => {
3   return new Date() > d;
4 }}
5 selected={date}
6 onChange={(date) => setDate(date)}
7/>;

Add a clear button to the datepicker

1<DatePicker
2isClearable
3selected={date}
4onChange={date => setDate(date)}
5/>

Reader

Allie Beazell
Allie Beazell
Retool
Aug 4, 2020
Copied