Okay, here’s a comprehensive article on building a datepicker component in React, aiming for approximately 5000 words. This will cover a wide range of topics, from basic setup to advanced features and considerations.
Building a Datepicker in React: A Comprehensive Guide
Datepickers are a ubiquitous element in modern web applications, providing a user-friendly way to select dates for forms, scheduling tools, data analysis interfaces, and countless other scenarios. While numerous pre-built datepicker libraries exist for React, building one from scratch offers invaluable learning opportunities and allows for complete customization to fit specific project needs. This guide will walk you through the process of creating a flexible, accessible, and robust datepicker component in React, covering everything from basic functionality to advanced features.
I. Project Setup and Basic Structure
Before diving into the component itself, we need to set up a basic React project. We’ll use create-react-app
for a quick and easy setup, but you can adapt these steps to your preferred build environment.
-
Create the Project:
bash
npx create-react-app react-datepicker-tutorial
cd react-datepicker-tutorial -
Install Dependencies (Optional – but recommended):
We’ll use a few helpful libraries to simplify date manipulation and handling keyboard events:
- date-fns: A modern, lightweight, and modular date utility library. It’s a great alternative to Moment.js, offering better tree-shaking and smaller bundle sizes.
- react-use: A collection of useful React hooks, including
useClickAway
which is helpful for closing the datepicker when clicking outside. (We’ll use this later)
bash
npm install date-fns react-use -
Component Structure:
Create a new file named
Datepicker.js
(orDatepicker.jsx
) within yoursrc
directory. We’ll start with a basic functional component structure:“`javascript
// src/Datepicker.js
import React, { useState } from ‘react’;
import { format, startOfMonth, endOfMonth, eachDayOfInterval, isSameDay, isSameMonth } from ‘date-fns’;function Datepicker() {
const [selectedDate, setSelectedDate] = useState(new Date()); // Start with today’s date
const [currentMonth, setCurrentMonth] = useState(new Date()); // Track the currently displayed monthreturn ( <div className="datepicker"> {/* Datepicker UI will go here */} <h1>{format(currentMonth, 'MMMM yyyy')}</h1> {/* Display the current month and year */} <button onClick={() => setCurrentMonth(dateFns.subMonths(currentMonth, 1))}>Previous</button> <button onClick={() => setCurrentMonth(dateFns.addMonths(currentMonth, 1))}>Next</button> </div> );
}
export default Datepicker;
“`
We have added next and previous buttons to go to the previous and next months. -
Import the Component:
“`javascript
// src/App.js
import React from ‘react’;
import Datepicker from ‘./Datepicker’;
import ‘./App.css’;function App() {
return ();
}export default App;
“`
-
Basic Styling (Optional):
Create a
Datepicker.css
file (or use styled-components, CSS modules, etc.) to add some basic styling:css
/* src/Datepicker.css */
.datepicker {
border: 1px solid #ccc;
border-radius: 4px;
padding: 10px;
font-family: sans-serif;
}
Import this css file into the Datepicker component.javascript
// src/Datepicker.js
import './Datepicker.css';
II. Building the Calendar Grid
The core of the datepicker is the calendar grid that displays the days of the month. We’ll use date-fns
to generate the necessary data.
-
Generate Days of the Month:
Inside the
Datepicker
component, add a function to generate an array of dates for the current month:“`javascript
// src/Datepicker.js
function Datepicker() {
// … (previous state and imports)const renderDays = () => { const startDate = startOfMonth(currentMonth); const endDate = endOfMonth(currentMonth); const days = eachDayOfInterval({ start: startDate, end: endDate }); return days.map((day) => ( <div key={day.toISOString()} className={`day ${isSameDay(day, selectedDate) ? 'selected' : ''}`} onClick={() => setSelectedDate(day)} > {format(day, 'd')} </div> )); }; return ( <div className="datepicker"> <h1>{format(currentMonth, 'MMMM yyyy')}</h1> <button onClick={() => setCurrentMonth(dateFns.subMonths(currentMonth, 1))}>Previous</button> <button onClick={() => setCurrentMonth(dateFns.addMonths(currentMonth, 1))}>Next</button> <div className="calendar-grid"> {renderDays()} </div> </div> );
}
“`startOfMonth(currentMonth)
: Gets the first day of thecurrentMonth
.endOfMonth(currentMonth)
: Gets the last day of thecurrentMonth
.eachDayOfInterval({ start: startDate, end: endDate })
: Returns an array of dates between thestartDate
andendDate
(inclusive).format(day, 'd')
: Formats the date to display only the day of the month (e.g., “1”, “15”, “31”).isSameDay(day, selectedDate)
: Checks if the currentday
is the same as theselectedDate
. We use this to apply a “selected” class.- We added basic styling to the calendar grid, and a
selected
class to the div representing the currently selected date.
-
Add Weekday Headers:
Let’s add headers for the days of the week (Sun, Mon, Tue, etc.):
“`javascript
// src/Datepicker.js
function Datepicker() {
// … (previous state, imports, and renderDays)const renderWeekdays = () => { const weekdays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; return weekdays.map((day) => ( <div key={day} className="weekday"> {day} </div> )); }; return ( <div className="datepicker"> {/*... previous and next month buttons */} <div className="calendar-grid"> {renderWeekdays()} {renderDays()} </div> </div> );
}
“`
-
Styling the Calendar Grid:
Update your
Datepicker.css
to style the grid and weekdays:“`css
/ src/Datepicker.css /
.calendar-grid {
display: grid;
grid-template-columns: repeat(7, 1fr); / 7 columns for the days of the week /
gap: 2px; / Add some spacing between days /
}.weekday {
text-align: center;
font-weight: bold;
padding: 5px;
border-bottom: 1px solid #ccc;
}.day {
text-align: center;
padding: 5px;
cursor: pointer; / Make days clickable /
border-radius: 4px;
}.day:hover {
background-color: #eee;
}.day.selected {
background-color: #007bff; / Highlight the selected day /
color: white;
}
“`
III. Handling Days from Previous/Next Months
Currently, the calendar only shows days from the currentMonth
. To make the calendar look complete, we need to include days from the previous and next months to fill out the first and last weeks.
-
Calculate Leading and Trailing Days:
We’ll modify the
renderDays
function to include these days:“`javascript
// src/Datepicker.js
import { startOfWeek, endOfWeek, addDays } from ‘date-fns’;
//…
const renderDays = () => {
const startDate = startOfWeek(startOfMonth(currentMonth)); // Start of the week of the first day
const endDate = endOfWeek(endOfMonth(currentMonth)); // End of the week of the last day
const days = eachDayOfInterval({ start: startDate, end: endDate });return days.map((day) => ( <div key={day.toISOString()} className={`day ${isSameDay(day, selectedDate) ? 'selected' : ''} ${isSameMonth(day, currentMonth) ? '' : 'other-month'} `} onClick={() => setSelectedDate(day)} > {format(day, 'd')} </div> )); };
“`
startOfWeek(startOfMonth(currentMonth))
: Gets the first day of the week containing the first day of the month. This will often be a day in the previous month.endOfWeek(endOfMonth(currentMonth))
: Gets the last day of the week containing the last day of the month. This will often be a day in the next month.isSameMonth(day, currentMonth)
: Checks if theday
belongs to thecurrentMonth
. We use this to apply another-month
class.
-
Styling Other Month Days:
Add a style for days that are not in the current month:
css
/* src/Datepicker.css */
.day.other-month {
color: #999; /* Lighter color for days outside the current month */
}
IV. Input Field and Datepicker Visibility
Now, let’s add an input field that will display the selected date and control the visibility of the calendar.
-
Add Input Field and State:
“`javascript
// src/Datepicker.js
import React, { useState, useRef } from ‘react’; // Import useRef
import { useClickAway } from ‘react-use’; // Import useClickAway
//…function Datepicker() {
const [selectedDate, setSelectedDate] = useState(null); // Initialize as null
const [currentMonth, setCurrentMonth] = useState(new Date());
const [isOpen, setIsOpen] = useState(false); // Control calendar visibility
const datepickerRef = useRef(null); // Ref for the entire datepickeruseClickAway(datepickerRef, () => { setIsOpen(false); // Close the calendar when clicking outside }); //... (renderWeekdays and renderDays functions) return ( <div className="datepicker" ref={datepickerRef}> <input type="text" value={selectedDate ? format(selectedDate, 'yyyy-MM-dd') : ''} onClick={() => setIsOpen(!isOpen)} readOnly // Prevent manual text input placeholder="Select a date" /> {isOpen && ( <div className="calendar"> {/* Calendar content (header, weekdays, days) */} <h1>{format(currentMonth, 'MMMM yyyy')}</h1> <button onClick={() => setCurrentMonth(dateFns.subMonths(currentMonth, 1))}>Previous</button> <button onClick={() => setCurrentMonth(dateFns.addMonths(currentMonth, 1))}>Next</button> <div className="calendar-grid"> {renderWeekdays()} {renderDays()} </div> </div> )} </div>
);
}“`
isOpen
: A state variable to control the visibility of the calendar.datepickerRef
: A ref attached to the outermostdiv
of the datepicker. We use this withuseClickAway
.useClickAway(datepickerRef, () => setIsOpen(false))
: This hook fromreact-use
closes the calendar when the user clicks anywhere outside the datepicker element.value={selectedDate ? format(selectedDate, 'yyyy-MM-dd') : ''}
: Displays the selected date in the input field, formatted as “yyyy-MM-dd”. If no date, display nothing.onClick={() => setIsOpen(!isOpen)}
: Toggles theisOpen
state when the input field is clicked.readOnly
: Prevents the user from typing directly into the input field.placeholder
: Adds placeholder text to guide the user.- We wrapped the calendar content (header, weekdays, days) in a
div
with the classcalendar
and conditionally render it based onisOpen
.
-
Styling the Input and Calendar Container:
“`css
/ src/Datepicker.css /
.datepicker {
position: relative; / Make the datepicker a positioning context /
display: inline-block; / Allow the datepicker to fit its content /
/ … (previous styles) /
}.calendar {
position: absolute; / Position the calendar relative to the datepicker /
top: 100%; / Position it below the input field /
left: 0;
background-color: white;
border: 1px solid #ccc;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15); / Add a subtle shadow /
z-index: 10; / Ensure the calendar appears above other elements /
}input[type=”text”] {
padding: 8px;
border: 1px solid #ccc;
border-radius: 4px;
width: 150px; / Adjust width as needed /
}
``
position: relative;
*on
.datepicker: This is crucial for absolutely positioning the calendar.
position: absolute;
*on
.calendar: Positions the calendar relative to the
.datepickercontainer.
top: 100%;
*: Places the calendar just below the input field.
z-index: 10;`: Ensures the calendar appears on top of other elements on the page.
* -
Update
setSelectedDate
and Close Calendar:
ModifyonClick
handler in renderDays to setisOpen
tofalse
.“`javascript
//src/Datepicker.js
const renderDays = () => {
// … (previous code)return days.map((day) => ( <div // ... (previous props) onClick={() => { setSelectedDate(day); setIsOpen(false); // Close the calendar after selection }} > {format(day, 'd')} </div> )); };
“`
V. Keyboard Navigation and Accessibility
A good datepicker should be fully navigable with the keyboard and accessible to users with assistive technologies.
-
Keyboard Event Handling:
We’ll add event listeners to the calendar container to handle arrow keys, Enter, and Escape.
“`javascript
// src/Datepicker.js
import React, { useState, useRef, useEffect } from ‘react’; // Import useEffect
//…function Datepicker() {
// … (previous state and refs)useEffect(() => { const handleKeyDown = (event) => { if (!isOpen) return; // Only handle keys if the calendar is open switch (event.key) { case 'ArrowLeft': setSelectedDate((prevDate) => prevDate ? addDays(prevDate, -1) : new Date() ); break; case 'ArrowRight': setSelectedDate((prevDate) => prevDate ? addDays(prevDate, 1) : new Date() ); break; case 'ArrowUp': setSelectedDate((prevDate) => prevDate ? addDays(prevDate, -7) : new Date() ); break; case 'ArrowDown': setSelectedDate((prevDate) => prevDate ? addDays(prevDate, 7) : new Date() ); break; case 'Enter': if (selectedDate && isSameMonth(selectedDate, currentMonth)) { //select only if selected date is in the current month setIsOpen(false); } break; case 'Escape': setIsOpen(false); break; default: break; } }; if (isOpen) { document.addEventListener('keydown', handleKeyDown); } return () => { document.removeEventListener('keydown', handleKeyDown); }; }, [isOpen, selectedDate, currentMonth]); // Dependencies for useEffect // ... (renderWeekdays, renderDays, and return statement)
}
“`useEffect
: We useuseEffect
to add and remove thekeydown
event listener. This ensures that the listener is only active when the calendar is open.handleKeyDown
: This function handles the key presses.ArrowLeft
,ArrowRight
,ArrowUp
,ArrowDown
: Move the selected date by one day or one week.Enter
: Selects the currently focused date (if it is in current month) and closes the calendar.Escape
: Closes the calendar.- The
return
function insideuseEffect
is a cleanup function that removes the event listener when the component unmounts or whenisOpen
changes. This prevents memory leaks.
-
Focus Management:
We need to ensure that focus is properly managed when the calendar opens and closes.
``javascript
.day[data-date=”${selectedDate.toISOString()}”]
// src/Datepicker.js
//...
const inputRef = useRef(null); // Ref for the input field
//...
useEffect(() => {
if (isOpen) {
// Focus the first day of the month when the calendar opens.
// Find a better way to focus a specific day element if needed.
const firstDayOfMonth = startOfMonth(currentMonth);
if(isSameMonth(selectedDate, currentMonth)){
const selectedDayElement = document.querySelector();
.day[data-date=”${firstDayOfMonth.toISOString()}”]`);
selectedDayElement?.focus();
} else{
const firstDayElement = document.querySelector(
firstDayElement?.focus();
}}
}, [isOpen, currentMonth, selectedDate]);
//…
//In renderDaysday ${isSameDay(day, selectedDate) ? ‘selected’ : ”}
${isSameMonth(day, currentMonth) ? ” : ‘other-month’}}
onClick={() => {
setSelectedDate(day);
setIsOpen(false);
inputRef.current.focus(); // Focus the input field after selection
}}
tabIndex={isSameMonth(day, currentMonth) ? 0 : -1} // Make days in the current month focusable
data-date={day.toISOString()}{format(day, 'd')}
//…
// In return() method, update input field with ref.
setIsOpen(!isOpen)}
readOnly
placeholder=”Select a date”
ref={inputRef} // Attach the ref to the input field
/>
“`inputRef
: A ref for the input field.- Inside renderDays, added
tabIndex={isSameMonth(day, currentMonth) ? 0 : -1}
: Makes the days in the current month focusable using the Tab key, while days from other months are not. - Inside renderDays,
inputRef.current.focus()
: Focuses the input field after a date is selected. - Added
data-date={day.toISOString()}
to the day elements for easier selection in theuseEffect
. - In the
useEffect
which handles calendar opening: We are manually managing the focus of day elements when calendar is opened. We usequerySelector
to find the appropriate day element and call.focus()
on it. If a date is already selected, and it is in the currently displayed month, we focus it. Otherwise, we focus the first day of the current month.
-
ARIA Attributes (Accessibility):
Add ARIA attributes to improve accessibility for screen readers.
“`javascript
// src/Datepicker.jsfunction Datepicker() {
// … (previous code)return ( <div className="datepicker" ref={datepickerRef} role="application"> <input // ... (previous props) aria-label="Select a date" aria-haspopup="dialog" // Indicates that the input opens a dialog aria-expanded={isOpen} // Indicates whether the calendar is open /> {isOpen && ( <div className="calendar" role="dialog" // The calendar acts as a dialog aria-label="Calendar" aria-modal="true" // Indicates that the calendar is modal (blocks interaction with the rest of the page) > <h1>{format(currentMonth, 'MMMM yyyy')}</h1> {/* next and previous button */} <div className="calendar-grid"> {renderWeekdays()} {renderDays()} </div> </div> )} </div> );
}
“`role="application"
: On the main datepicker container. This tells assistive technologies that this is a custom widget.aria-label="Select a date"
: Provides a label for the input field.aria-haspopup="dialog"
: Indicates that the input field opens a dialog (the calendar).aria-expanded={isOpen}
: Indicates whether the calendar is currently open or closed.role="dialog"
: On the calendar container. This indicates that the calendar is a dialog window.aria-label="Calendar"
: Provides a label for the calendar.aria-modal="true"
: Indicates that the calendar is modal, meaning it prevents interaction with the rest of the page until it’s closed.- Inside renderDays add
aria-selected
andaria-label
:
javascript
<div
//...other props
aria-selected={isSameDay(day, selectedDate)} // Indicates whether the day is selected
aria-label={format(day, 'MMMM dd, yyyy')} // Provides a full date label for screen readers
>
{format(day, 'd')}
</div>
VI. Advanced Features (Optional)
Let’s explore some more advanced features you might want to add to your datepicker.
-
Date Range Selection:
To support selecting a range of dates (start and end), you’ll need to modify the state and logic:
“`javascript
// src/Datepicker.js
import { isWithinInterval } from ‘date-fns’; // Import isWithinIntervalfunction Datepicker() {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [hoveredDate, setHoveredDate] = useState(null); // For highlighting the range on hover
//…const renderDays = () => { const startDateOfWeek = startOfWeek(startOfMonth(currentMonth)); const endDateOfWeek = endOfWeek(endOfMonth(currentMonth)); const days = eachDayOfInterval({ start: startDateOfWeek, end: endDateOfWeek }); return days.map((day) => { const isSelected = (startDate && isSameDay(day, startDate)) || (endDate && isSameDay(day, endDate)); const isInRange = startDate && endDate && isWithinInterval(day, { start: startDate, end: endDate }); const isHoveredRange = startDate && !endDate && hoveredDate && isWithinInterval(day, {start: startDate, end: hoveredDate}); return ( <div key={day.toISOString()} className={`day ${isSelected ? 'selected' : ''} ${isInRange || isHoveredRange? 'in-range' : ''} ${isSameMonth(day, currentMonth) ? '' : 'other-month'} `} onClick={() => { if (!startDate) { setStartDate(day); } else if (!endDate) { setEndDate(day); setIsOpen(false); inputRef.current.focus(); } else { setStartDate(day); setEndDate(null); } }} onMouseEnter={() => setHoveredDate(day)} onMouseLeave={() => setHoveredDate(null)} tabIndex={isSameMonth(day, currentMonth) ? 0 : -1} data-date={day.toISOString()} aria-selected={isSelected} aria-label={format(day, 'MMMM dd, yyyy')} > {format(day, 'd')} </div> ); }); }; return ( <div className="datepicker" ref={datepickerRef} role="application"> <input type="text" value={ startDate && endDate ? `${format(startDate, 'yyyy-MM-dd')} - ${format(endDate, 'yyyy-MM-dd')}` : startDate ? `${format(startDate, 'yyyy-MM-dd')} -` : '' } onClick={() => setIsOpen(!isOpen)} readOnly placeholder="Select a date range" ref={inputRef} aria-label="Select a date range" aria-haspopup="dialog" aria-expanded={isOpen} /> {/* ... rest of the component ... */} </div> );
}
“`startDate
,endDate
: State variables to store the start and end dates of the range.hoveredDate
: A state variable to track the date currently being hovered over, used to visually highlight the range during selection.isWithinInterval(day, { start: startDate, end: endDate })
: Checks if aday
falls within the selected range.- Modified
onClick
: Logic to handle setting thestartDate
andendDate
. If start date is not selected, select it. If end date is not selected, select it, close calendar, and refocus to input. If both dates are selected, restart selection by setting selected date to the clicked date, and end date tonull
. onMouseEnter
,onMouseLeave
: Used to updatehoveredDate
for range highlighting.isInRange
: Added to the className, this will be defined in the css.- Update input field
value
to reflect range selection.
Add styling for the range:
css
/* src/Datepicker.css */
.day.in-range {
background-color: #b3d9ff; /* Light blue background for days in the range */
} -
Disabling Dates:
You might want to disable certain dates (e.g., past dates, weekends, specific holidays).
“`javascript
// src/Datepicker.js
function Datepicker({ disabledDates = [] }) { // Receive disabledDates as a prop
// …const renderDays = () => {
// … (previous code)return days.map((day) => { const isDisabled = disabledDates.some((disabledDate) => isSameDay(day, disabledDate)); return ( <div key={day.toISOString()} className={`day ${isSameDay(day, selectedDate) ? 'selected' : ''} ${isSameMonth(day, currentMonth) ? '' : 'other-month'} ${isDisabled ? 'disabled' : ''} `} onClick={() => { if (!isDisabled) { setSelectedDate(day); setIsOpen(false); inputRef.current.focus(); } }} tabIndex={isSameMonth(day, currentMonth) && !isDisabled ? 0 : -1} data-date={day.toISOString()} aria-selected={isSameDay(day, selectedDate)} aria-label={format(day, 'MMMM dd, yyyy')} aria-disabled={isDisabled} // Add aria-disabled attribute > {format(day, 'd')} </div> ); });
};
// …
}
“`disabledDates
: An array of dates that should be disabled, passed as a prop.isDisabled
: Checks if the currentday
is in thedisabledDates
array.- Added
disabled
to className. onClick
: Only allows selection if the date is not disabled.aria-disabled={isDisabled}
: Adds thearia-disabled
attribute for accessibility.- Update
tabIndex
to also depend onisDisabled
.
Add a style for disabled days:
“`css
/ src/Datepicker.css /
.day.disabled {
color: #ccc; / Gray out disabled days /
cursor: not-allowed; / Change cursor to indicate unclickable /
background-color: #f9f9f9;
}.day.disabled:hover {
background-color: #f9f9f9; / Prevent hover effect on disabled days /
}
“`To use this, you would pass an array of dates to the
Datepicker
component:javascript
// src/App.js
import { parseISO } from 'date-fns';
//...
<Datepicker disabledDates={[parseISO('2024-03-08'), parseISO('2024-03-15')]} /> -
Customizable Week Start:
By default date-fns considers Sunday as the start of the week. You might want to allow users to start the week on a different day (e.g., Monday).
“`javascript
// src/Datepicker.js
function Datepicker({ weekStartsOn = 0 }) { // Default to Sunday (0)
// … (previous code)const renderWeekdays = () => { const weekdays = []; let day = startOfWeek(new Date(), { weekStartsOn }); //start the week based on the provided day for (let i = 0; i < 7; i++) { weekdays.push(format(day, 'EEE')); // Use 'EEE' for short weekday names (Sun, Mon, etc.) day = addDays(day, 1); } return weekdays.map((day) => ( <div key={day} className="weekday"> {day} </div> )); }; const renderDays = () => { const startDate = startOfWeek(startOfMonth(currentMonth), { weekStartsOn }); const endDate = endOfWeek(endOfMonth(currentMonth), { weekStartsOn }); //....Rest of renderDays }
}
``
weekStartsOn
*: Added to the parameters of Datepicker component. This prop specifies the day of the week to start on (0 for Sunday, 1 for Monday, etc.). It defaults to 0 (Sunday).
renderDays
* Updatedto take
weekStartsOninto account while getting the start and end dates.
renderWeekdays
* Updatedmethod to show the correct weekdays, starting from
weekStartsOn`. -
Localization:
To support different languages and date formats, you can use
date-fns
‘s locale support.“`javascript
// src/Datepicker.js
import { format, startOfMonth, endOfMonth, eachDayOfInterval, isSameDay, isSameMonth, startOfWeek, endOfWeek, addDays } from ‘date-fns’;
import { enUS, fr, es } from ‘date-fns/locale’; // Import desired localesfunction Datepicker({ locale = enUS }) { // Default to enUS
//… (previous code, including weekStartsOn change.)
const renderWeekdays = () => {
const weekdays = [];
let day = startOfWeek(new Date(), { weekStartsOn, locale: locale });for (let i = 0; i < 7; i++) { weekdays.push(format(day, 'EEE', { locale: locale })); day = addDays(day, 1); } return weekdays.map((day) => ( <div key={day} className="weekday"> {day} </div> )); };
const renderDays = () => {
const startDate = startOfWeek(startOfMonth(currentMonth), { weekStartsOn: weekStartsOn, locale: locale});
const endDate = endOfWeek(endOfMonth(currentMonth), { weekStartsOn: weekStartsOn, locale: locale });
const days = eachDayOfInterval({ start: startDate, end: endDate });return days.map((day) => { //... (previous code in renderDays) return ( <div // ... (previous props) aria-label={format(day, 'PPP', { locale: locale })} // Use 'PPP' for localized long date format > {format(day, 'd')} </div> ); });
};
return (
setIsOpen(!isOpen)}
readOnly
placeholder=”Select a date”
ref={inputRef}
aria-label=”Select a date”
aria-haspopup=”dialog”
aria-expanded={isOpen}
/>
{/ … rest of the component … /});
}
“`locale
: A prop to specify the locale to use (e.g.,enUS
,fr
,es
). Defaults toenUS
.- Import