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
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)}/>
<DatePicker label="Birth Date" placeholder="Choose your birth date" value={birthDate} onDateSelect={setBirthDate} required/>
<DatePicker label="Event Date" dateFormat="DD MMM YYYY" value={eventDate} onDateSelect={setEventDate}/>
<DatePicker label="Appointment Date" value={appointmentDate} onDateSelect={setAppointmentDate} minDate="2024-01-01" maxDate="2024-12-31"/>
Prop | Type | Default | Description |
---|---|---|---|
value | string | - | Selected date in YYYY-MM-DD format |
onDateSelect | (date: string) => void | - | Callback when date is selected |
placeholder | string | 'Choose date' | Placeholder text when no date selected |
label | string | - | Label text above input |
disabled | boolean | false | Disable date picker interactions |
size | ComponentSize | 'md' | Input size (xs, sm, md, lg, xl) |
variant | ComponentVariant | 'default' | Visual style variant |
state | ComponentState | '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 |
minDate | string | - | Minimum selectable date (YYYY-MM-DD) |
maxDate | string | - | Maximum selectable date (YYYY-MM-DD) |
markedDates | CalendarProps['markedDates'] | - | Special dates to highlight on calendar |
showIcon | boolean | true | Show calendar/chevron icon |
iconPosition | 'left' | 'right' | 'right' | Position of the icon |
customIcon | React.ReactNode | - | Custom icon component |
closeOnSelect | boolean | true | Close calendar after date selection |
animationDuration | number | 300 | Animation duration in milliseconds |
backdropOpacity | number | 0.5 | Backdrop opacity (0-1) |
borderRadius | keyof Theme['components']['borderRadius'] | 'md' | Border radius value |
helperText | string | - | Helper text below input |
error | string | - | Error message (overrides helperText) |
required | boolean | false | Show required asterisk in label |
animated | boolean | true | Enable animations |
onChange | (date: string) => void | - | Alternative callback for date changes |
Prop | Type | Description |
---|---|---|
style | ViewStyle | Container style overrides |
inputStyle | ViewStyle | Input container style overrides |
labelStyle | TextStyle | Label text style overrides |
placeholderStyle | TextStyle | Placeholder text style overrides |
calendarStyle | ViewStyle | Calendar modal style overrides |
Variant | Description | Use Case |
---|---|---|
default | Standard input styling | General date selection |
primary | Primary color theme | Important date fields |
secondary | Secondary color theme | Secondary date inputs |
outline | Outlined border style | Emphasized borders |
filled | Filled background style | Form consistency |
ghost | Minimal transparent style | Subtle date inputs |
success | Success state styling | Validated dates |
error | Error state styling | Invalid dates |
warning | Warning state styling | Attention-needed dates |
info | Information styling | Informational dates |
Format | Example | Use Case |
---|---|---|
DD/MM/YYYY | 25/12/2024 | European format |
MM/DD/YYYY | 12/25/2024 | American format |
YYYY-MM-DD | 2024-12-25 | ISO format, database storage |
DD MMM YYYY | 25 Dec 2024 | Human-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}/>
<DatePicker animated={true} animationDuration={150} backdropOpacity={0.3}/>
<DatePicker animated={true} animationDuration={500} backdropOpacity={0.7}/>
<DatePicker animated={false}/>
User Experience
Validation
Performance
React.memo
for date pickers that don’t change frequentlyInternationalization