Skip to content

DatePicker

DatePicker provides a comprehensive date selection solution with built-in animations, multiple date formats, validation support, and Portal-based calendar overlay. It features smooth transitions, customizable styling, and seamless integration with form systems.

import { DatePicker } from 'rnc-theme';
<DatePicker
placeholder="Select date"
onDateSelect={(date) => console.log(date)}
/>
PropTypeDefaultDescription
valuestring-Selected date in YYYY-MM-DD format
onDateSelect(date: string) => void-Callback when date is selected
placeholderstring'Choose date'Placeholder text when no date selected
labelstring-Label text above input
disabledbooleanfalseDisable date picker interactions
sizeComponentSize'md'Input size (xs, sm, md, lg, xl)
variantComponentVariant'default'Visual style variant
stateComponentState'default'Component state (default, error, success)
dateFormat'DD/MM/YYYY' | 'MM/DD/YYYY' | 'YYYY-MM-DD' | 'DD MMM YYYY''DD/MM/YYYY'Display format for selected date
minDatestring-Minimum selectable date (YYYY-MM-DD)
maxDatestring-Maximum selectable date (YYYY-MM-DD)
markedDatesCalendarProps['markedDates']-Special dates to highlight on calendar
showIconbooleantrueShow calendar/chevron icon
iconPosition'left' | 'right''right'Position of the icon
customIconReact.ReactNode-Custom icon component
closeOnSelectbooleantrueClose calendar after date selection
animationDurationnumber300Animation duration in milliseconds
backdropOpacitynumber0.5Backdrop opacity (0-1)
borderRadiuskeyof Theme['components']['borderRadius']'md'Border radius value
helperTextstring-Helper text below input
errorstring-Error message (overrides helperText)
requiredbooleanfalseShow required asterisk in label
animatedbooleantrueEnable animations
onChange(date: string) => void-Alternative callback for date changes
PropTypeDescription
styleViewStyleContainer style overrides
inputStyleViewStyleInput container style overrides
labelStyleTextStyleLabel text style overrides
placeholderStyleTextStylePlaceholder text style overrides
calendarStyleViewStyleCalendar modal style overrides
VariantDescriptionUse Case
defaultStandard input stylingGeneral date selection
primaryPrimary color themeImportant date fields
secondarySecondary color themeSecondary date inputs
outlineOutlined border styleEmphasized borders
filledFilled background styleForm consistency
ghostMinimal transparent styleSubtle date inputs
successSuccess state stylingValidated dates
errorError state stylingInvalid dates
warningWarning state stylingAttention-needed dates
infoInformation stylingInformational dates
FormatExampleUse Case
DD/MM/YYYY25/12/2024European format
MM/DD/YYYY12/25/2024American format
YYYY-MM-DD2024-12-25ISO format, database storage
DD MMM YYYY25 Dec 2024Human-readable format
const ProfileForm = () => {
const [birthDate, setBirthDate] = useState('');
const [joinDate, setJoinDate] = useState('');
return (
<VStack spacing="lg" padding="xl">
<DatePicker
label="Date of Birth"
placeholder="Select your birth date"
value={birthDate}
onDateSelect={setBirthDate}
dateFormat="DD MMM YYYY"
maxDate={new Date().toISOString().split('T')[0]}
required
helperText="Must be 18 years or older"
/>
<DatePicker
label="Join Date"
placeholder="Select join date"
value={joinDate}
onDateSelect={setJoinDate}
variant="outline"
minDate="2020-01-01"
helperText="When did you join the company?"
/>
</VStack>
);
};
<VStack spacing="md" padding="lg">
<DatePicker
size="xs"
placeholder="Extra Small"
label="XS DatePicker"
/>
<DatePicker
size="sm"
placeholder="Small"
label="SM DatePicker"
/>
<DatePicker
size="md"
placeholder="Medium"
label="MD DatePicker"
/>
<DatePicker
size="lg"
placeholder="Large"
label="LG DatePicker"
/>
<DatePicker
size="xl"
placeholder="Extra Large"
label="XL DatePicker"
/>
</VStack>
const ValidationExample = () => {
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [errors, setErrors] = useState({});
const validateDates = () => {
const newErrors = {};
if (!startDate) {
newErrors.startDate = 'Start date is required';
}
if (!endDate) {
newErrors.endDate = 'End date is required';
}
if (startDate && endDate && new Date(startDate) >= new Date(endDate)) {
newErrors.endDate = 'End date must be after start date';
}
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
return (
<VStack spacing="lg" padding="xl">
<DatePicker
label="Start Date"
value={startDate}
onDateSelect={(date) => {
setStartDate(date);
setErrors(prev => ({ ...prev, startDate: null }));
}}
state={errors.startDate ? 'error' : startDate ? 'success' : 'default'}
error={errors.startDate}
required
/>
<DatePicker
label="End Date"
value={endDate}
onDateSelect={(date) => {
setEndDate(date);
setErrors(prev => ({ ...prev, endDate: null }));
}}
minDate={startDate || undefined}
state={errors.endDate ? 'error' : endDate ? 'success' : 'default'}
error={errors.endDate}
required
/>
<Button onPress={validateDates} variant="primary">
<ButtonText>Validate Dates</ButtonText>
</Button>
</VStack>
);
};
const EventBooking = () => {
const [eventDate, setEventDate] = useState('');
const [reminderDate, setReminderDate] = useState('');
// Mark weekends and holidays
const markedDates = {
'2024-12-25': { marked: true, dotColor: 'red', disabled: true },
'2024-01-01': { marked: true, dotColor: 'red', disabled: true },
// Add more special dates
};
const today = new Date().toISOString().split('T')[0];
const maxEventDate = new Date();
maxEventDate.setFullYear(maxEventDate.getFullYear() + 1);
return (
<VStack spacing="lg" padding="xl">
<Text variant="title">Book Your Event</Text>
<DatePicker
label="Event Date"
placeholder="Select event date"
value={eventDate}
onDateSelect={setEventDate}
dateFormat="DD MMM YYYY"
minDate={today}
maxDate={maxEventDate.toISOString().split('T')[0]}
markedDates={markedDates}
variant="primary"
size="lg"
helperText="Events can be booked up to 1 year in advance"
required
/>
<DatePicker
label="Reminder Date"
placeholder="Set reminder date"
value={reminderDate}
onDateSelect={setReminderDate}
dateFormat="DD MMM YYYY"
minDate={today}
maxDate={eventDate || undefined}
variant="outline"
iconPosition="left"
helperText="Get notified before your event"
/>
<HStack spacing="md">
<Button variant="outline" flex={1}>
<ButtonText>Clear</ButtonText>
</Button>
<Button variant="primary" flex={1} disabled={!eventDate}>
<ButtonText>Book Event</ButtonText>
</Button>
</HStack>
</VStack>
);
};
const CustomStyledDatePicker = () => {
const [selectedDate, setSelectedDate] = useState('');
return (
<DatePicker
label="Custom Styled DatePicker"
value={selectedDate}
onDateSelect={setSelectedDate}
variant="filled"
borderRadius="lg"
style={{
backgroundColor: '#f8f9fa',
padding: 16,
borderRadius: 12,
}}
inputStyle={{
borderWidth: 2,
borderColor: '#e9ecef',
shadowOffset: { width: 0, height: 2 },
shadowOpacity: 0.1,
shadowRadius: 4,
}}
labelStyle={{
fontSize: 16,
fontWeight: '700',
color: '#495057',
}}
calendarStyle={{
borderRadius: 16,
shadowOffset: { width: 0, height: 8 },
shadowOpacity: 0.3,
shadowRadius: 12,
}}
customIcon={<CalendarIcon size={24} color="#6c757d" />}
animationDuration={400}
backdropOpacity={0.7}
/>
);
};
const DateRangePicker = () => {
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const [isSelectingEnd, setIsSelectingEnd] = useState(false);
const handleStartDateSelect = (date) => {
setStartDate(date);
if (endDate && new Date(date) > new Date(endDate)) {
setEndDate('');
}
setIsSelectingEnd(true);
};
const handleEndDateSelect = (date) => {
setEndDate(date);
setIsSelectingEnd(false);
};
// Generate marked dates for range
const getMarkedDates = () => {
if (!startDate || !endDate) return {};
const marked = {};
const start = new Date(startDate);
const end = new Date(endDate);
const current = new Date(start);
while (current <= end) {
const dateString = current.toISOString().split('T')[0];
marked[dateString] = {
color: '#007bff',
textColor: 'white',
startingDay: dateString === startDate,
endingDay: dateString === endDate,
};
current.setDate(current.getDate() + 1);
}
return marked;
};
return (
<VStack spacing="md" padding="lg">
<Text variant="subtitle">Select Date Range</Text>
<HStack spacing="md">
<DatePicker
label="From"
placeholder="Start date"
value={startDate}
onDateSelect={handleStartDateSelect}
state={isSelectingEnd ? 'success' : 'default'}
markedDates={getMarkedDates()}
flex={1}
/>
<DatePicker
label="To"
placeholder="End date"
value={endDate}
onDateSelect={handleEndDateSelect}
minDate={startDate || undefined}
markedDates={getMarkedDates()}
disabled={!startDate}
flex={1}
/>
</HStack>
{startDate && endDate && (
<Card>
<Text>
Selected range: {formatDate(startDate, 'DD MMM YYYY')} - {formatDate(endDate, 'DD MMM YYYY')}
</Text>
<Text variant="caption">
Duration: {Math.ceil((new Date(endDate) - new Date(startDate)) / (1000 * 60 * 60 * 24))} days
</Text>
</Card>
)}
</VStack>
);
};
<DatePicker
animated={true}
animationDuration={300}
backdropOpacity={0.5}
/>

User Experience

  • Use clear, descriptive labels for all date inputs
  • Provide helper text for date constraints or format expectations
  • Show validation feedback immediately after user interaction
  • Consider the user’s locale when choosing date formats

Validation

  • Always validate date ranges on both client and server side
  • Provide clear error messages for invalid date selections
  • Use appropriate min/max date constraints to guide user selection
  • Handle edge cases like leap years and month boundaries

Performance

  • Use React.memo for date pickers that don’t change frequently
  • Avoid creating new date objects in render functions
  • Consider lazy loading calendar components for better initial load times
  • Implement proper cleanup for animation timers

Internationalization

  • Support multiple date formats based on user locale
  • Consider right-to-left (RTL) layout support
  • Use appropriate calendar systems for different regions
  • Provide localized month and day names