A responsive and accessible date range picker component built with React
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Standalone input field components for custom layouts and advanced use cases. These components handle date input, validation, and formatting without the calendar interface, allowing you to build custom date picker experiences.
Input fields component for date range display and manual entry, providing dual input fields for start and end dates.
/**
* Date range input fields without calendar
* @param props - DateRangePickerInput configuration
* @returns Input fields for date range entry
*/
function DateRangePickerInput(props: DateRangePickerInputProps): ReactElement;
interface DateRangePickerInputProps {
// Input field IDs (required)
startDateId: string;
endDateId: string;
// Display values
startDate?: string;
endDate?: string;
startDatePlaceholderText?: string;
endDatePlaceholderText?: string;
// State
isStartDateFocused?: boolean;
isEndDateFocused?: boolean;
isFocused?: boolean; // Actual DOM focus state
disabled?: boolean;
required?: boolean;
readOnly?: boolean;
showClearDates?: boolean;
showCaret?: boolean; // Show caret indicator
// Styling
noBorder?: boolean;
block?: boolean;
small?: boolean;
regular?: boolean;
isRTL?: boolean; // Right-to-left layout support
// Layout
openDirection?: 'up' | 'down'; // Direction to open calendar overlay
verticalSpacing?: number; // Vertical spacing in pixels (non-negative integer)
// Icons
showDefaultInputIcon?: boolean;
inputIconPosition?: 'before' | 'after';
customInputIcon?: ReactNode;
customArrowIcon?: ReactNode;
customCloseIcon?: ReactNode;
// Event handlers
onStartDateChange?: (dateString: string) => void;
onEndDateChange?: (dateString: string) => void;
onStartDateFocus?: () => void;
onEndDateFocus?: () => void;
onStartDateShiftTab?: () => void;
onEndDateTab?: () => void;
onClearDates?: () => void;
onKeyDownArrowDown?: () => void; // Arrow down key handler
onKeyDownQuestionMark?: () => void; // Question mark key handler
// Accessibility
startDateAriaLabel?: string;
endDateAriaLabel?: string;
screenReaderMessage?: string;
// Content
children?: ReactNode; // Child elements to render
// Internationalization
phrases?: object;
}Usage Examples:
import React, { useState } from "react";
import { DateRangePickerInput } from "react-dates";
// Basic date range input
function BasicDateRangeInput() {
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [startFocused, setStartFocused] = useState(false);
const [endFocused, setEndFocused] = useState(false);
return (
<DateRangePickerInput
startDateId="start_date"
endDateId="end_date"
startDate={startDate}
endDate={endDate}
onStartDateChange={setStartDate}
onEndDateChange={setEndDate}
isStartDateFocused={startFocused}
isEndDateFocused={endFocused}
onStartDateFocus={() => setStartFocused(true)}
onEndDateFocus={() => setEndFocused(true)}
startDatePlaceholderText="Check-in"
endDatePlaceholderText="Check-out"
showClearDates={true}
/>
);
}
// Custom styled input with validation
function CustomDateRangeInput({ onValidDatesChange }) {
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [startFocused, setStartFocused] = useState(false);
const [endFocused, setEndFocused] = useState(false);
const [errors, setErrors] = useState({});
const validateDate = (dateString) => {
const date = moment(dateString, 'MM/DD/YYYY', true);
return date.isValid() && date.isAfter(moment().subtract(1, 'day'));
};
const handleStartDateChange = (dateString) => {
setStartDate(dateString);
const isValid = validateDate(dateString);
setErrors(prev => ({ ...prev, start: !isValid }));
if (isValid && validateDate(endDate)) {
onValidDatesChange({
startDate: moment(dateString, 'MM/DD/YYYY'),
endDate: moment(endDate, 'MM/DD/YYYY')
});
}
};
const handleEndDateChange = (dateString) => {
setEndDate(dateString);
const isValid = validateDate(dateString);
setErrors(prev => ({ ...prev, end: !isValid }));
if (isValid && validateDate(startDate)) {
onValidDatesChange({
startDate: moment(startDate, 'MM/DD/YYYY'),
endDate: moment(dateString, 'MM/DD/YYYY')
});
}
};
return (
<div>
<DateRangePickerInput
startDateId="trip_start"
endDateId="trip_end"
startDate={startDate}
endDate={endDate}
onStartDateChange={handleStartDateChange}
onEndDateChange={handleEndDateChange}
isStartDateFocused={startFocused}
isEndDateFocused={endFocused}
onStartDateFocus={() => setStartFocused(true)}
onEndDateFocus={() => setEndFocused(true)}
showDefaultInputIcon={true}
block={true}
/>
{errors.start && <div style={{ color: 'red' }}>Invalid start date</div>}
{errors.end && <div style={{ color: 'red' }}>Invalid end date</div>}
</div>
);
}Controller component that manages date range input logic, validation, and formatting.
/**
* Controller for date range input logic and validation
* @param props - DateRangePickerInputController configuration
* @returns Managed date range input component
*/
function DateRangePickerInputController(props: DateRangePickerInputControllerProps): ReactElement;
interface DateRangePickerInputControllerProps {
// Date state
startDate?: moment.Moment | null;
endDate?: moment.Moment | null;
// Input field IDs (required)
startDateId: string;
endDateId: string;
// Display format and placeholders
startDatePlaceholderText?: string;
endDatePlaceholderText?: string;
displayFormat?: (() => string) | string;
// State management
isStartDateFocused?: boolean;
isEndDateFocused?: boolean;
isFocused?: boolean; // Actual DOM focus state
disabled?: boolean;
required?: boolean;
readOnly?: boolean;
showClearDates?: boolean;
showCaret?: boolean; // Show caret indicator
keepOpenOnDateSelect?: boolean; // Keep picker open after date selection
reopenPickerOnClearDates?: boolean; // Reopen picker when dates are cleared
// Portal and layout
withFullScreenPortal?: boolean; // Use full screen portal mode
openDirection?: 'up' | 'down'; // Direction to open calendar
verticalSpacing?: number; // Vertical spacing in pixels (non-negative integer)
isRTL?: boolean; // Right-to-left layout support
// Date validation
minimumNights?: number; // Minimum nights between dates (non-negative integer)
isOutsideRange?: (day: moment.Moment) => boolean; // Function to determine if day is outside selectable range
// Event handlers
onDatesChange?: ({ startDate, endDate }: {
startDate: moment.Moment | null;
endDate: moment.Moment | null;
}) => void;
onFocusChange?: (focusedInput: 'startDate' | 'endDate' | null) => void;
onClose?: () => void; // Callback when picker closes
onKeyDownArrowDown?: () => void; // Arrow down key handler
onKeyDownQuestionMark?: () => void; // Question mark key handler
// Styling
noBorder?: boolean;
block?: boolean;
small?: boolean;
regular?: boolean;
// Icons
showDefaultInputIcon?: boolean;
inputIconPosition?: 'before' | 'after';
customInputIcon?: ReactNode;
customArrowIcon?: ReactNode;
customCloseIcon?: ReactNode;
// Accessibility
startDateAriaLabel?: string;
endDateAriaLabel?: string;
screenReaderMessage?: string;
// Content
children?: ReactNode; // Child elements to render
// Internationalization
phrases?: object;
}Public Methods:
// Date handling methods (accessible via ref)
onStartDateChange(startDateString: string): void;
onEndDateChange(endDateString: string): void;
onStartDateFocus(): void;
onEndDateFocus(): void;
clearDates(): void;
getDisplayFormat(): string;
getDateString(date: moment.Moment | null): string;Usage Examples:
import React, { useState, useRef } from "react";
import { DateRangePickerInputController } from "react-dates";
import moment from "moment";
// Controlled date range input
function ControlledDateRangeInput() {
const [startDate, setStartDate] = useState(null);
const [endDate, setEndDate] = useState(null);
const [focusedInput, setFocusedInput] = useState(null);
const controllerRef = useRef(null);
const handleDatesChange = ({ startDate, endDate }) => {
setStartDate(startDate);
setEndDate(endDate);
// Custom validation
if (startDate && endDate && endDate.isBefore(startDate)) {
// Swap dates if end is before start
setStartDate(endDate);
setEndDate(startDate);
}
};
const clearAllDates = () => {
if (controllerRef.current) {
controllerRef.current.clearDates();
}
};
return (
<div>
<DateRangePickerInputController
ref={controllerRef}
startDate={startDate}
endDate={endDate}
startDateId="start_input"
endDateId="end_input"
onDatesChange={handleDatesChange}
onFocusChange={setFocusedInput}
isStartDateFocused={focusedInput === 'startDate'}
isEndDateFocused={focusedInput === 'endDate'}
displayFormat="MMM D, YYYY"
showClearDates={true}
/>
<button onClick={clearAllDates}>Clear All Dates</button>
</div>
);
}Input field component for single date display and manual entry.
/**
* Single date input field without calendar
* @param props - SingleDatePickerInput configuration
* @returns Input field for single date entry
*/
function SingleDatePickerInput(props: SingleDatePickerInputProps): ReactElement;
interface SingleDatePickerInputProps {
// Required
id: string;
// Display
placeholder?: string;
displayValue?: string;
ariaLabel?: string;
screenReaderMessage?: string;
// State
focused?: boolean;
disabled?: boolean;
required?: boolean;
readOnly?: boolean;
showClearDate?: boolean;
// Styling
noBorder?: boolean;
block?: boolean;
small?: boolean;
regular?: boolean;
// Icons
showDefaultInputIcon?: boolean;
inputIconPosition?: 'before' | 'after';
customInputIcon?: ReactNode;
customCloseIcon?: ReactNode;
// Event handlers
onChange?: (dateString: string) => void;
onClearDate?: () => void;
onFocus?: () => void;
onKeyDownShiftTab?: () => void;
onKeyDownTab?: () => void;
onKeyDownArrowDown?: () => void;
onKeyDownQuestionMark?: () => void;
// Internationalization
phrases?: object;
}Usage Examples:
import React, { useState } from "react";
import { SingleDatePickerInput } from "react-dates";
import moment from "moment";
// Basic single date input
function BasicSingleDateInput() {
const [date, setDate] = useState('');
const [focused, setFocused] = useState(false);
const handleDateChange = (dateString) => {
setDate(dateString);
// Validate date format
const parsedDate = moment(dateString, 'MM/DD/YYYY', true);
if (parsedDate.isValid()) {
console.log('Valid date selected:', parsedDate.format('YYYY-MM-DD'));
}
};
return (
<SingleDatePickerInput
id="birthday_input"
placeholder="Select your birthday"
displayValue={date}
onChange={handleDateChange}
focused={focused}
onFocus={() => setFocused(true)}
showClearDate={true}
showDefaultInputIcon={true}
/>
);
}
// Formatted date input with custom validation
function FormattedDateInput({ format = 'YYYY-MM-DD', onValidDate }) {
const [inputValue, setInputValue] = useState('');
const [isValid, setIsValid] = useState(true);
const handleChange = (dateString) => {
setInputValue(dateString);
const parsedDate = moment(dateString, format, true);
const valid = parsedDate.isValid();
setIsValid(valid);
if (valid) {
onValidDate(parsedDate);
}
};
return (
<div>
<SingleDatePickerInput
id="formatted_date"
placeholder={`Enter date (${format})`}
displayValue={inputValue}
onChange={handleChange}
block={true}
customInputIcon={
<span style={{ color: isValid ? 'green' : 'red' }}>📅</span>
}
/>
{!isValid && inputValue && (
<div style={{ color: 'red', fontSize: '12px' }}>
Please enter a valid date in {format} format
</div>
)}
</div>
);
}Controller component that manages single date input logic, validation, and formatting with full picker integration.
/**
* Controller for single date input logic with picker integration
* @param props - SingleDatePickerInputController configuration
* @returns Managed single date input component with picker
*/
function SingleDatePickerInputController(props: SingleDatePickerInputControllerProps): ReactElement;
interface SingleDatePickerInputControllerProps {
// Date state
date?: moment.Moment | null; // Selected date value
focused?: boolean; // Whether input is focused
// Required props
id: string; // Required input field ID
onDateChange: (date: moment.Moment | null) => void; // Required callback when date changes
onFocusChange: (arg: { focused: boolean }) => void; // Required callback for focus changes
// Display and placeholders
placeholder?: string; // Input placeholder text
displayFormat?: string | (() => string); // Date display format
// State management
isFocused?: boolean; // Actual DOM focus state
disabled?: boolean; // Disabled state
required?: boolean; // Required field
readOnly?: boolean; // Read-only state
showClearDate?: boolean; // Show clear date button
showCaret?: boolean; // Show caret indicator
// Portal and layout
openDirection?: 'up' | 'down'; // Direction to open calendar
verticalSpacing?: number; // Vertical spacing in pixels (non-negative integer)
isRTL?: boolean; // Right-to-left layout support
// Picker behavior
keepOpenOnDateSelect?: boolean; // Keep open after date selection
reopenPickerOnClearDate?: boolean; // Reopen after clearing date
// Date validation
isOutsideRange?: (day: moment.Moment) => boolean; // Outside range validation
// Event handlers
onClose?: () => void; // Callback when picker closes
onKeyDownArrowDown?: () => void; // Arrow down key handler
onKeyDownQuestionMark?: () => void; // Question mark key handler
// Styling
noBorder?: boolean; // Remove border styling
block?: boolean; // Block-level display
small?: boolean; // Small size variant
regular?: boolean; // Regular size variant
// Icons
showDefaultInputIcon?: boolean; // Show default calendar icon
inputIconPosition?: 'before' | 'after'; // Position of input icon
customInputIcon?: ReactNode; // Custom input icon
customCloseIcon?: ReactNode; // Custom close icon
// Accessibility
ariaLabel?: string; // Accessibility label
screenReaderMessage?: string; // Screen reader message
// Content
children?: ReactNode; // Child elements to render
// Internationalization
phrases?: object; // Internationalization phrases
}Usage Examples:
import React, { useState } from "react";
import { SingleDatePickerInputController } from "react-dates";
import moment from "moment";
// Controlled single date input with picker
function ControlledSingleDateInput() {
const [date, setDate] = useState(null);
const [focused, setFocused] = useState(false);
return (
<SingleDatePickerInputController
id="controlled_date"
date={date}
onDateChange={setDate}
focused={focused}
onFocusChange={({ focused }) => setFocused(focused)}
placeholder="Select a date"
showClearDate={true}
showDefaultInputIcon={true}
isOutsideRange={(day) => moment().diff(day) > 0} // No past dates
/>
);
}
// Advanced date picker with validation
function ValidatedDatePicker({ onValidDate, minDate, maxDate }) {
const [date, setDate] = useState(null);
const [focused, setFocused] = useState(false);
const isOutsideRange = (day) => {
if (minDate && day.isBefore(minDate, 'day')) return true;
if (maxDate && day.isAfter(maxDate, 'day')) return true;
return false;
};
const handleDateChange = (newDate) => {
setDate(newDate);
if (newDate && !isOutsideRange(newDate)) {
onValidDate(newDate);
}
};
return (
<SingleDatePickerInputController
id="validated_date"
date={date}
onDateChange={handleDateChange}
focused={focused}
onFocusChange={({ focused }) => setFocused(focused)}
isOutsideRange={isOutsideRange}
displayFormat="MMM D, YYYY"
block={true}
onClose={() => console.log('Picker closed')}
/>
);
}All input components support custom icons:
// Custom calendar icon
const customIcon = <CalendarIcon size={16} color="#007bff" />;
// Custom clear button
const customClearIcon = <XIcon size={14} color="#dc3545" />;
<SingleDatePickerInput
customInputIcon={customIcon}
customCloseIcon={customClearIcon}
inputIconPosition="before"
/>// Date format validation
const validateDateFormat = (dateString, format = 'MM/DD/YYYY') => {
const date = moment(dateString, format, true);
return date.isValid();
};
// Date range validation
const validateDateRange = (date, minDate, maxDate) => {
const momentDate = moment(date);
return momentDate.isBetween(minDate, maxDate, 'day', '[]');
};
// Business day validation
const isBusinessDay = (dateString) => {
const date = moment(dateString);
const dayOfWeek = date.day();
return dayOfWeek !== 0 && dayOfWeek !== 6; // Not Sunday or Saturday
};Install with Tessl CLI
npx tessl i tessl/npm-react-dates