Customizable Date Picker for React with extensive internationalization and accessibility support
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
React Day Picker provides a type-safe selection system supporting single date, multiple dates, and date range selection with both controlled and uncontrolled modes.
The library supports three main selection modes with optional required validation.
/**
* Selection mode types
*/
type Mode = "single" | "multiple" | "range";
/**
* Type-safe selected value based on selection mode
*/
type SelectedValue<T extends DayPickerProps> =
T["mode"] extends "single" ? Date | undefined :
T["mode"] extends "multiple" ? Date[] | undefined :
T["mode"] extends "range" ? DateRange | undefined :
never;
/**
* Type-safe selection handler based on selection mode
*/
type SelectHandler<T extends DayPickerProps> = (
value: SelectedValue<T>,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;Select a single date from the calendar.
/**
* Props for single date selection mode
*/
interface PropsSingle {
mode: "single";
/** The selected date */
selected?: Date;
/** The default selected date for uncontrolled mode */
defaultSelected?: Date;
/** Event handler when a date is selected */
onSelect?: (
date: Date | undefined,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}
/**
* Props for required single date selection
*/
interface PropsSingleRequired {
mode: "single";
required: true;
/** The selected date (required) */
selected?: Date;
/** The default selected date for uncontrolled mode (required) */
defaultSelected?: Date;
/** Event handler when a date is selected (cannot be undefined) */
onSelect?: (
date: Date,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}Usage Examples:
import React, { useState } from "react";
import { DayPicker } from "react-day-picker";
// Controlled single selection
function ControlledSingle() {
const [selected, setSelected] = useState<Date>();
return (
<DayPicker
mode="single"
selected={selected}
onSelect={setSelected}
/>
);
}
// Uncontrolled single selection
function UncontrolledSingle() {
return (
<DayPicker
mode="single"
defaultSelected={new Date()}
onSelect={(date) => console.log("Selected:", date)}
/>
);
}
// Required single selection
function RequiredSingle() {
const [selected, setSelected] = useState<Date>(new Date());
return (
<DayPicker
mode="single"
required
selected={selected}
onSelect={setSelected}
/>
);
}Select multiple individual dates from the calendar.
/**
* Props for multiple date selection mode
*/
interface PropsMulti {
mode: "multiple";
/** The selected dates array */
selected?: Date[];
/** The default selected dates for uncontrolled mode */
defaultSelected?: Date[];
/** Minimum number of dates that must be selected */
min?: number;
/** Maximum number of dates that can be selected */
max?: number;
/** Event handler when dates are selected */
onSelect?: (
dates: Date[] | undefined,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}
/**
* Props for required multiple date selection
*/
interface PropsMultiRequired {
mode: "multiple";
required: true;
/** The selected dates array (required) */
selected?: Date[];
/** The default selected dates for uncontrolled mode (required) */
defaultSelected?: Date[];
/** Minimum number of dates that must be selected */
min?: number;
/** Maximum number of dates that can be selected */
max?: number;
/** Event handler when dates are selected (cannot be empty) */
onSelect?: (
dates: Date[],
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}Usage Examples:
// Controlled multiple selection
function ControlledMultiple() {
const [selected, setSelected] = useState<Date[]>([]);
return (
<DayPicker
mode="multiple"
selected={selected}
onSelect={setSelected}
max={5} // limit to 5 dates
/>
);
}
// Multiple selection with constraints
function ConstrainedMultiple() {
const [selected, setSelected] = useState<Date[]>([]);
return (
<DayPicker
mode="multiple"
selected={selected}
onSelect={setSelected}
min={2}
max={7}
disabled={{ dayOfWeek: [0, 6] }} // disable weekends
/>
);
}Select a continuous range of dates with start and end dates.
/**
* Props for date range selection mode
*/
interface PropsRange {
mode: "range";
/** The selected date range */
selected?: DateRange;
/** The default selected range for uncontrolled mode */
defaultSelected?: DateRange;
/** Minimum number of days in the range */
min?: number;
/** Maximum number of days in the range */
max?: number;
/** Event handler when a range is selected */
onSelect?: (
range: DateRange | undefined,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}
/**
* Props for required date range selection
*/
interface PropsRangeRequired {
mode: "range";
required: true;
/** The selected date range (required) */
selected?: DateRange;
/** The default selected range for uncontrolled mode (required) */
defaultSelected?: DateRange;
/** Minimum number of days in the range */
min?: number;
/** Maximum number of days in the range */
max?: number;
/** Event handler when a range is selected (cannot be undefined) */
onSelect?: (
range: DateRange,
triggerDate: Date,
modifiers: Modifiers,
e: React.MouseEvent
) => void;
}
/**
* Date range interface
*/
interface DateRange {
from: Date | undefined;
to?: Date | undefined;
}Usage Examples:
// Controlled range selection
function ControlledRange() {
const [range, setRange] = useState<DateRange | undefined>();
return (
<DayPicker
mode="range"
selected={range}
onSelect={setRange}
numberOfMonths={2}
/>
);
}
// Range selection with constraints
function ConstrainedRange() {
const [range, setRange] = useState<DateRange | undefined>();
const handleSelect = (newRange: DateRange | undefined) => {
// Custom validation logic
if (newRange?.from && newRange?.to) {
const daysDiff = Math.abs(
newRange.to.getTime() - newRange.from.getTime()
) / (1000 * 60 * 60 * 24);
if (daysDiff > 14) {
alert("Range cannot exceed 14 days");
return;
}
}
setRange(newRange);
};
return (
<DayPicker
mode="range"
selected={range}
onSelect={handleSelect}
min={3} // minimum 3 days
max={14} // maximum 14 days
/>
);
}
// Range selection with custom styling
function StyledRange() {
const [range, setRange] = useState<DateRange | undefined>();
return (
<DayPicker
mode="range"
selected={range}
onSelect={setRange}
modifiersClassNames={{
range_start: "range-start",
range_middle: "range-middle",
range_end: "range-end"
}}
/>
);
}Hook for accessing selection state in custom components.
/**
* Hook providing access to the DayPicker context
* @returns DayPicker context with selection state and handlers
*/
function useDayPicker<T extends DayPickerProps>(): DayPickerContext<T>;
interface DayPickerContext<T extends DayPickerProps> {
/** The DayPicker props */
dayPickerProps: T;
/** Current selected value */
selected: SelectedValue<T>;
/** Selection handler function */
select: SelectHandler<T>;
/** Function to check if a date is selected */
isSelected?: (date: Date) => boolean;
/** Calendar months data */
months: CalendarMonth[];
/** Next navigable month */
nextMonth?: Date;
/** Previous navigable month */
previousMonth?: Date;
/** Navigate to specific month */
goToMonth: (month: Date) => void;
/** Get modifiers for a day */
getModifiers: (day: CalendarDay) => Modifiers;
/** Custom components */
components: CustomComponents;
/** CSS class names */
classNames: ClassNames;
/** CSS styles */
styles?: Partial<Styles>;
/** Accessibility labels */
labels: Labels;
/** Date formatters */
formatters: Formatters;
}Usage Example:
import { useDayPicker } from "react-day-picker";
function CustomFooter() {
const { selected, mode } = useDayPicker();
if (mode === "single" && selected) {
return <p>Selected: {selected.toDateString()}</p>;
}
if (mode === "range" && selected?.from) {
return (
<p>
{selected.from.toDateString()}
{selected.to ? ` - ${selected.to.toDateString()}` : " (select end date)"}
</p>
);
}
return <p>No date selected</p>;
}
// Usage in DayPicker
<DayPicker
mode="single"
components={{ Footer: CustomFooter }}
/>Install with Tessl CLI
npx tessl i tessl/npm-react-day-picker