0
# Date and Time Components
1
2
NextUI provides comprehensive date and time components with internationalization support, accessibility features, and integration with modern date handling libraries for building robust temporal interfaces.
3
4
## Capabilities
5
6
### Calendar
7
8
A full-featured calendar component for single date selection with navigation, keyboard support, and customizable appearance.
9
10
```typescript { .api }
11
interface CalendarProps<T extends DateValue = DateValue> {
12
/** Current selected date */
13
value?: T | null;
14
/** Default selected date */
15
defaultValue?: T | null;
16
/** Minimum selectable date */
17
minValue?: DateValue | null;
18
/** Maximum selectable date */
19
maxValue?: DateValue | null;
20
/** Function to determine if a date is unavailable */
21
isDateUnavailable?: (date: DateValue) => boolean;
22
/** Auto focus on mount */
23
autoFocus?: boolean;
24
/** Currently focused date */
25
focusedValue?: DateValue | null;
26
/** Default focused date */
27
defaultFocusedValue?: DateValue | null;
28
/** Calendar width */
29
calendarWidth?: number;
30
/** Number of months to display */
31
visibleMonths?: number;
32
/** Page behavior for navigation */
33
pageBehavior?: PageBehavior;
34
/** Weekday display style */
35
weekdayStyle?: "narrow" | "short" | "long";
36
/** Show month and year picker dropdowns */
37
showMonthAndYearPickers?: boolean;
38
/** Whether calendar is disabled */
39
isDisabled?: boolean;
40
/** Whether calendar is read-only */
41
isReadOnly?: boolean;
42
/** Whether calendar is invalid */
43
isInvalid?: boolean;
44
/** Calendar color theme */
45
color?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
46
/** Show helper content */
47
showHelper?: boolean;
48
/** Content above calendar */
49
topContent?: React.ReactNode;
50
/** Content below calendar */
51
bottomContent?: React.ReactNode;
52
/** Error message */
53
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
54
/** Validation function */
55
validate?: (value: MappedDateValue<T>) => ValidationError | true | null | undefined;
56
/** Validation behavior */
57
validationBehavior?: "aria" | "native";
58
/** Custom CSS class */
59
className?: string;
60
/** Slot-based styling */
61
classNames?: SlotsToClasses<CalendarSlots>;
62
/** Focus change handler */
63
onFocusChange?: (date: CalendarDate) => void;
64
/** Value change handler */
65
onChange?: (value: MappedDateValue<T>) => void;
66
}
67
68
type CalendarSlots =
69
| "base" | "prevButton" | "nextButton" | "headerWrapper"
70
| "header" | "title" | "content" | "gridWrapper" | "grid"
71
| "gridHeader" | "gridHeaderRow" | "gridHeaderCell" | "gridBody"
72
| "gridBodyRow" | "cell" | "cellButton" | "pickerWrapper"
73
| "monthPicker" | "yearPicker" | "helperWrapper" | "errorMessage";
74
75
type PageBehavior = "single" | "visible";
76
77
function Calendar<T extends DateValue = DateValue>(props: CalendarProps<T>): JSX.Element;
78
79
/**
80
* Hook for Calendar state management
81
*/
82
function useCalendar<T extends DateValue = DateValue>(props: CalendarProps<T>): {
83
Component: React.ElementType;
84
state: CalendarState;
85
slots: Record<CalendarSlots, string>;
86
classNames: SlotsToClasses<CalendarSlots>;
87
getCalendarProps: () => any;
88
getButtonProps: (direction: "previous" | "next") => any;
89
getGridProps: () => any;
90
getCellProps: (date: CalendarDate) => any;
91
};
92
```
93
94
### Range Calendar
95
96
A calendar component for selecting date ranges with visual range indicators and dual navigation.
97
98
```typescript { .api }
99
interface RangeCalendarProps<T extends DateValue = DateValue> {
100
/** Current selected date range */
101
value?: RangeValue<T> | null;
102
/** Default selected date range */
103
defaultValue?: RangeValue<T> | null;
104
/** Minimum selectable date */
105
minValue?: DateValue | null;
106
/** Maximum selectable date */
107
maxValue?: DateValue | null;
108
/** Function to determine if a date is unavailable */
109
isDateUnavailable?: (date: DateValue) => boolean;
110
/** Auto focus on mount */
111
autoFocus?: boolean;
112
/** Currently focused date */
113
focusedValue?: DateValue | null;
114
/** Default focused date */
115
defaultFocusedValue?: DateValue | null;
116
/** Calendar width */
117
calendarWidth?: number;
118
/** Number of months to display */
119
visibleMonths?: number;
120
/** Page behavior for navigation */
121
pageBehavior?: PageBehavior;
122
/** Weekday display style */
123
weekdayStyle?: "narrow" | "short" | "long";
124
/** Show month and year picker dropdowns */
125
showMonthAndYearPickers?: boolean;
126
/** Whether calendar is disabled */
127
isDisabled?: boolean;
128
/** Whether calendar is read-only */
129
isReadOnly?: boolean;
130
/** Whether calendar is invalid */
131
isInvalid?: boolean;
132
/** Calendar color theme */
133
color?: "foreground" | "primary" | "secondary" | "success" | "warning" | "danger";
134
/** Show helper content */
135
showHelper?: boolean;
136
/** Content above calendar */
137
topContent?: React.ReactNode;
138
/** Content below calendar */
139
bottomContent?: React.ReactNode;
140
/** Error message */
141
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
142
/** Validation function */
143
validate?: (value: RangeValue<MappedDateValue<T>>) => ValidationError | true | null | undefined;
144
/** Validation behavior */
145
validationBehavior?: "aria" | "native";
146
/** Allow non-contiguous ranges */
147
allowsNonContiguousRanges?: boolean;
148
/** Custom CSS class */
149
className?: string;
150
/** Slot-based styling */
151
classNames?: SlotsToClasses<CalendarSlots>;
152
/** Focus change handler */
153
onFocusChange?: (date: CalendarDate) => void;
154
/** Value change handler */
155
onChange?: (value: RangeValue<MappedDateValue<T>>) => void;
156
}
157
158
function RangeCalendar<T extends DateValue = DateValue>(props: RangeCalendarProps<T>): JSX.Element;
159
160
/**
161
* Hook for RangeCalendar state management
162
*/
163
function useRangeCalendar<T extends DateValue = DateValue>(props: RangeCalendarProps<T>): {
164
Component: React.ElementType;
165
state: RangeCalendarState;
166
slots: Record<CalendarSlots, string>;
167
classNames: SlotsToClasses<CalendarSlots>;
168
getRangeCalendarProps: () => any;
169
getButtonProps: (direction: "previous" | "next") => any;
170
getGridProps: () => any;
171
getCellProps: (date: CalendarDate) => any;
172
};
173
```
174
175
**Calendar Usage Examples:**
176
177
```typescript
178
import { Calendar, RangeCalendar } from "@nextui-org/react";
179
import { CalendarDate, today, getLocalTimeZone, isWeekend } from "@internationalized/date";
180
181
function CalendarExamples() {
182
const [date, setDate] = useState<CalendarDate>(today(getLocalTimeZone()));
183
const [dateRange, setDateRange] = useState<RangeValue<CalendarDate>>({
184
start: today(getLocalTimeZone()),
185
end: today(getLocalTimeZone()).add({ weeks: 1 }),
186
});
187
188
// Mark weekends as unavailable
189
const isDateUnavailable = (date: DateValue) => isWeekend(date, "en-US");
190
191
return (
192
<div className="space-y-8">
193
{/* Single date calendar */}
194
<div>
195
<h3 className="text-lg font-semibold mb-4">Single Date Selection</h3>
196
<Calendar
197
aria-label="Date (No Selection)"
198
value={date}
199
onChange={setDate}
200
color="primary"
201
showMonthAndYearPickers
202
isDateUnavailable={isDateUnavailable}
203
/>
204
</div>
205
206
{/* Date range calendar */}
207
<div>
208
<h3 className="text-lg font-semibold mb-4">Date Range Selection</h3>
209
<RangeCalendar
210
aria-label="Date Range"
211
value={dateRange}
212
onChange={setDateRange}
213
color="secondary"
214
visibleMonths={2}
215
pageBehavior="visible"
216
/>
217
</div>
218
219
{/* Calendar with validation */}
220
<div>
221
<h3 className="text-lg font-semibold mb-4">Calendar with Validation</h3>
222
<Calendar
223
value={date}
224
onChange={setDate}
225
minValue={today(getLocalTimeZone())}
226
maxValue={today(getLocalTimeZone()).add({ months: 1 })}
227
validate={(value) => {
228
if (value && isWeekend(value, "en-US")) {
229
return "Weekends are not allowed";
230
}
231
return true;
232
}}
233
errorMessage={(validation) =>
234
validation.isInvalid ? validation.validationErrors[0] : undefined
235
}
236
/>
237
</div>
238
</div>
239
);
240
}
241
```
242
243
### Calendar Context
244
245
Context system for sharing calendar state and configuration.
246
247
```typescript { .api }
248
interface CalendarProviderProps {
249
children: React.ReactNode;
250
value: CalendarContextValue;
251
}
252
253
interface CalendarContextValue {
254
state: CalendarState | RangeCalendarState;
255
slots: Record<CalendarSlots, string>;
256
classNames?: SlotsToClasses<CalendarSlots>;
257
visibleMonths: number;
258
weekdayStyle: "narrow" | "short" | "long";
259
}
260
261
const CalendarProvider: React.FC<CalendarProviderProps>;
262
263
/**
264
* Hook to access calendar context
265
* @throws Error if used outside CalendarProvider
266
*/
267
function useCalendarContext(): CalendarContextValue;
268
```
269
270
### Date Input
271
272
A specialized input component for entering dates with segment-based editing and keyboard navigation.
273
274
```typescript { .api }
275
interface DateInputProps<T extends DateValue = DateValue> {
276
/** Input label */
277
label?: React.ReactNode;
278
/** Current date value */
279
value?: T | null;
280
/** Default date value */
281
defaultValue?: T | null;
282
/** Input placeholder when empty */
283
placeholder?: string;
284
/** Helper description text */
285
description?: React.ReactNode;
286
/** Error message */
287
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
288
/** Validation function */
289
validate?: (value: MappedDateValue<T>) => ValidationError | true | null | undefined;
290
/** Validation behavior */
291
validationBehavior?: "aria" | "native";
292
/** Minimum selectable date */
293
minValue?: DateValue | null;
294
/** Maximum selectable date */
295
maxValue?: DateValue | null;
296
/** Whether input is required */
297
isRequired?: boolean;
298
/** Whether input is read-only */
299
isReadOnly?: boolean;
300
/** Whether input is disabled */
301
isDisabled?: boolean;
302
/** Whether input is invalid */
303
isInvalid?: boolean;
304
/** Auto focus on mount */
305
autoFocus?: boolean;
306
/** Input size */
307
size?: "sm" | "md" | "lg";
308
/** Border radius */
309
radius?: "none" | "sm" | "md" | "lg" | "full";
310
/** Visual variant */
311
variant?: "flat" | "bordered" | "underlined" | "faded";
312
/** Color theme */
313
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
314
/** Label placement */
315
labelPlacement?: "inside" | "outside" | "outside-left";
316
/** Whether input takes full width */
317
fullWidth?: boolean;
318
/** Show clear button */
319
isClearable?: boolean;
320
/** Disable animations */
321
disableAnimation?: boolean;
322
/** Start content */
323
startContent?: React.ReactNode;
324
/** End content */
325
endContent?: React.ReactNode;
326
/** Custom CSS class */
327
className?: string;
328
/** Slot-based styling */
329
classNames?: SlotsToClasses<DateInputSlots>;
330
/** Value change handler */
331
onChange?: (value: MappedDateValue<T>) => void;
332
}
333
334
type DateInputSlots =
335
| "base" | "label" | "inputWrapper" | "input" | "innerWrapper"
336
| "segment" | "helperWrapper" | "description" | "errorMessage";
337
338
type DateInputValue = CalendarDate | CalendarDateTime | ZonedDateTime;
339
340
function DateInput<T extends DateValue = DateValue>(props: DateInputProps<T>): JSX.Element;
341
342
/**
343
* Hook for DateInput state management
344
*/
345
function useDateInput<T extends DateValue = DateValue>(props: DateInputProps<T>): {
346
Component: React.ElementType;
347
state: DateFieldState;
348
slots: Record<DateInputSlots, string>;
349
classNames: SlotsToClasses<DateInputSlots>;
350
getDateInputProps: () => any;
351
getLabelProps: () => any;
352
getInputProps: () => any;
353
getSegmentProps: (segment: DateSegment) => any;
354
};
355
```
356
357
### Time Input
358
359
A specialized input component for entering time values with segment-based editing.
360
361
```typescript { .api }
362
interface TimeInputProps<T extends TimeValue = TimeValue> {
363
/** Input label */
364
label?: React.ReactNode;
365
/** Current time value */
366
value?: T | null;
367
/** Default time value */
368
defaultValue?: T | null;
369
/** Input placeholder when empty */
370
placeholder?: string;
371
/** Helper description text */
372
description?: React.ReactNode;
373
/** Error message */
374
errorMessage?: React.ReactNode | ((v: ValidationResult) => React.ReactNode);
375
/** Validation function */
376
validate?: (value: MappedTimeValue<T>) => ValidationError | true | null | undefined;
377
/** Validation behavior */
378
validationBehavior?: "aria" | "native";
379
/** Minimum selectable time */
380
minValue?: TimeValue | null;
381
/** Maximum selectable time */
382
maxValue?: TimeValue | null;
383
/** Whether input is required */
384
isRequired?: boolean;
385
/** Whether input is read-only */
386
isReadOnly?: boolean;
387
/** Whether input is disabled */
388
isDisabled?: boolean;
389
/** Whether input is invalid */
390
isInvalid?: boolean;
391
/** Auto focus on mount */
392
autoFocus?: boolean;
393
/** Input size */
394
size?: "sm" | "md" | "lg";
395
/** Border radius */
396
radius?: "none" | "sm" | "md" | "lg" | "full";
397
/** Visual variant */
398
variant?: "flat" | "bordered" | "underlined" | "faded";
399
/** Color theme */
400
color?: "default" | "primary" | "secondary" | "success" | "warning" | "danger";
401
/** Label placement */
402
labelPlacement?: "inside" | "outside" | "outside-left";
403
/** Whether input takes full width */
404
fullWidth?: boolean;
405
/** Show clear button */
406
isClearable?: boolean;
407
/** Disable animations */
408
disableAnimation?: boolean;
409
/** Start content */
410
startContent?: React.ReactNode;
411
/** End content */
412
endContent?: React.ReactNode;
413
/** Custom CSS class */
414
className?: string;
415
/** Slot-based styling */
416
classNames?: SlotsToClasses<DateInputSlots>;
417
/** Value change handler */
418
onChange?: (value: MappedTimeValue<T>) => void;
419
}
420
421
type TimeInputValue = Time;
422
423
function TimeInput<T extends TimeValue = TimeValue>(props: TimeInputProps<T>): JSX.Element;
424
425
/**
426
* Hook for TimeInput state management
427
*/
428
function useTimeInput<T extends TimeValue = TimeValue>(props: TimeInputProps<T>): {
429
Component: React.ElementType;
430
state: TimeFieldState;
431
slots: Record<DateInputSlots, string>;
432
classNames: SlotsToClasses<DateInputSlots>;
433
getTimeInputProps: () => any;
434
getLabelProps: () => any;
435
getInputProps: () => any;
436
getSegmentProps: (segment: DateSegment) => any;
437
};
438
```
439
440
### Date Input Components
441
442
Lower-level components for building custom date input interfaces.
443
444
```typescript { .api }
445
interface DateInputGroupProps {
446
/** Input group content */
447
children?: React.ReactNode;
448
/** Custom CSS class */
449
className?: string;
450
}
451
452
interface DateInputFieldProps {
453
/** Field content */
454
children?: React.ReactNode;
455
/** Custom CSS class */
456
className?: string;
457
}
458
459
interface DateInputSegmentProps {
460
/** Segment content */
461
segment: DateSegment;
462
/** Segment state */
463
state: DateFieldState | TimeFieldState;
464
/** Custom CSS class */
465
className?: string;
466
}
467
468
function DateInputGroup(props: DateInputGroupProps): JSX.Element;
469
function DateInputField(props: DateInputFieldProps): JSX.Element;
470
function DateInputSegment(props: DateInputSegmentProps): JSX.Element;
471
```
472
473
**Date Input Usage Examples:**
474
475
```typescript
476
import { DateInput, TimeInput } from "@nextui-org/react";
477
import { CalendarDate, Time, now, getLocalTimeZone } from "@internationalized/date";
478
479
function DateInputExamples() {
480
const [date, setDate] = useState<CalendarDate>(new CalendarDate(2024, 4, 4));
481
const [time, setTime] = useState<Time>(new Time(11, 45));
482
483
return (
484
<div className="space-y-6 max-w-xs">
485
{/* Basic date input */}
486
<DateInput
487
label="Birth date"
488
value={date}
489
onChange={setDate}
490
placeholderValue={new CalendarDate(1995, 11, 6)}
491
/>
492
493
{/* Date input with validation */}
494
<DateInput
495
label="Appointment date"
496
isRequired
497
description="Select a date for your appointment"
498
validate={(value) => {
499
if (!value) return "Please select a date";
500
const today = now(getLocalTimeZone()).date;
501
if (value.compare(today) < 0) {
502
return "Date cannot be in the past";
503
}
504
return true;
505
}}
506
errorMessage={(validation) =>
507
validation.isInvalid ? validation.validationErrors[0] : undefined
508
}
509
/>
510
511
{/* Time input */}
512
<TimeInput
513
label="Meeting time"
514
value={time}
515
onChange={setTime}
516
description="Enter the meeting time"
517
/>
518
519
{/* Date input with custom format */}
520
<DateInput
521
label="Event date"
522
variant="bordered"
523
color="secondary"
524
size="sm"
525
showMonthAndYearPickers
526
maxValue={today(getLocalTimeZone()).add({ years: 1 })}
527
/>
528
</div>
529
);
530
}
531
```
532
533
### Date Picker
534
535
A composite component combining date input with calendar popup for intuitive date selection.
536
537
```typescript { .api }
538
interface DatePickerProps<T extends DateValue = DateValue>
539
extends Omit<DateInputProps<T>, "size"> {
540
/** Date picker size */
541
size?: "sm" | "md" | "lg";
542
/** Selector icon (calendar icon) */
543
selectorIcon?: React.ReactNode;
544
/** Calendar width */
545
calendarWidth?: number;
546
/** Number of months to display */
547
visibleMonths?: number;
548
/** Page behavior for calendar navigation */
549
pageBehavior?: PageBehavior;
550
/** Calendar props override */
551
calendarProps?: Partial<CalendarProps<T>>;
552
/** Show month and year picker dropdowns */
553
showMonthAndYearPickers?: boolean;
554
/** Close calendar on selection */
555
shouldCloseOnSelect?: boolean;
556
/** Custom CSS class */
557
className?: string;
558
/** Slot-based styling */
559
classNames?: SlotsToClasses<DatePickerSlots>;
560
}
561
562
type DatePickerSlots =
563
| "base" | "label" | "inputWrapper" | "input" | "innerWrapper"
564
| "segment" | "helperWrapper" | "description" | "errorMessage"
565
| "selectorButton" | "selectorIcon" | "popoverContent" | "calendar";
566
567
function DatePicker<T extends DateValue = DateValue>(props: DatePickerProps<T>): JSX.Element;
568
569
/**
570
* Hook for DatePicker state management
571
*/
572
function useDatePicker<T extends DateValue = DateValue>(props: DatePickerProps<T>): {
573
Component: React.ElementType;
574
state: DatePickerState;
575
slots: Record<DatePickerSlots, string>;
576
classNames: SlotsToClasses<DatePickerSlots>;
577
getDatePickerProps: () => any;
578
getPopoverProps: () => any;
579
getCalendarProps: () => any;
580
getSelectorButtonProps: () => any;
581
};
582
```
583
584
### Date Range Picker
585
586
A composite component for selecting date ranges with input fields and calendar popup.
587
588
```typescript { .api }
589
interface DateRangePickerProps<T extends DateValue = DateValue>
590
extends Omit<DateInputProps<T>, "value" | "defaultValue" | "onChange"> {
591
/** Current selected date range */
592
value?: RangeValue<T> | null;
593
/** Default selected date range */
594
defaultValue?: RangeValue<T> | null;
595
/** Date picker size */
596
size?: "sm" | "md" | "lg";
597
/** Selector icon (calendar icon) */
598
selectorIcon?: React.ReactNode;
599
/** Calendar width */
600
calendarWidth?: number;
601
/** Number of months to display */
602
visibleMonths?: number;
603
/** Page behavior for calendar navigation */
604
pageBehavior?: PageBehavior;
605
/** Calendar props override */
606
calendarProps?: Partial<RangeCalendarProps<T>>;
607
/** Show month and year picker dropdowns */
608
showMonthAndYearPickers?: boolean;
609
/** Close calendar on selection */
610
shouldCloseOnSelect?: boolean;
611
/** Custom CSS class */
612
className?: string;
613
/** Slot-based styling */
614
classNames?: SlotsToClasses<DatePickerSlots>;
615
/** Value change handler */
616
onChange?: (value: RangeValue<MappedDateValue<T>>) => void;
617
}
618
619
function DateRangePicker<T extends DateValue = DateValue>(props: DateRangePickerProps<T>): JSX.Element;
620
621
/**
622
* Hook for DateRangePicker state management
623
*/
624
function useDateRangePicker<T extends DateValue = DateValue>(props: DateRangePickerProps<T>): {
625
Component: React.ElementType;
626
state: DateRangePickerState;
627
slots: Record<DatePickerSlots, string>;
628
classNames: SlotsToClasses<DatePickerSlots>;
629
getDateRangePickerProps: () => any;
630
getPopoverProps: () => any;
631
getCalendarProps: () => any;
632
getSelectorButtonProps: () => any;
633
};
634
```
635
636
### Date Range Picker Field
637
638
A specialized input field component for the date range picker.
639
640
```typescript { .api }
641
interface DateRangePickerFieldProps {
642
/** Field content */
643
children?: React.ReactNode;
644
/** Custom CSS class */
645
className?: string;
646
}
647
648
function DateRangePickerField(props: DateRangePickerFieldProps): JSX.Element;
649
```
650
651
**Date Picker Usage Examples:**
652
653
```typescript
654
import { DatePicker, DateRangePicker, Button } from "@nextui-org/react";
655
import { CalendarDate, today, getLocalTimeZone } from "@internationalized/date";
656
657
function DatePickerExamples() {
658
const [selectedDate, setSelectedDate] = useState<CalendarDate | null>(null);
659
const [dateRange, setDateRange] = useState<RangeValue<CalendarDate> | null>(null);
660
661
return (
662
<div className="space-y-6 max-w-sm">
663
{/* Basic date picker */}
664
<DatePicker
665
label="Birth date"
666
value={selectedDate}
667
onChange={setSelectedDate}
668
showMonthAndYearPickers
669
/>
670
671
{/* Date picker with constraints */}
672
<DatePicker
673
label="Appointment date"
674
variant="bordered"
675
color="primary"
676
minValue={today(getLocalTimeZone())}
677
maxValue={today(getLocalTimeZone()).add({ months: 3 })}
678
defaultValue={today(getLocalTimeZone())}
679
description="Select a future date within 3 months"
680
/>
681
682
{/* Date range picker */}
683
<DateRangePicker
684
label="Stay duration"
685
value={dateRange}
686
onChange={setDateRange}
687
visibleMonths={2}
688
pageBehavior="visible"
689
color="secondary"
690
/>
691
692
{/* Date range picker with validation */}
693
<DateRangePicker
694
label="Project timeline"
695
variant="bordered"
696
validate={(value) => {
697
if (!value) return "Please select a date range";
698
if (value.start && value.end) {
699
const duration = value.end.calendar.toJulianDay(value.end) -
700
value.start.calendar.toJulianDay(value.start);
701
if (duration < 7) {
702
return "Project must be at least 1 week long";
703
}
704
if (duration > 365) {
705
return "Project cannot exceed 1 year";
706
}
707
}
708
return true;
709
}}
710
errorMessage={(validation) =>
711
validation.isInvalid ? validation.validationErrors[0] : undefined
712
}
713
/>
714
715
{/* Custom styled date picker */}
716
<DatePicker
717
label="Custom Date Picker"
718
size="lg"
719
radius="sm"
720
variant="faded"
721
shouldCloseOnSelect={false}
722
calendarProps={{
723
classNames: {
724
base: "bg-background",
725
headerWrapper: "pt-4 bg-background",
726
prevButton: "border-1 border-default-200",
727
nextButton: "border-1 border-default-200",
728
}
729
}}
730
classNames={{
731
inputWrapper: "border-1 border-default-200 bg-background",
732
input: "text-sm",
733
}}
734
/>
735
</div>
736
);
737
}
738
```
739
740
## Date and Time Component Types
741
742
```typescript { .api }
743
// Core date/time types from @internationalized/date
744
type DateValue = CalendarDate | CalendarDateTime | ZonedDateTime;
745
type TimeValue = Time;
746
type MappedDateValue<T> = T extends ZonedDateTime ? ZonedDateTime :
747
T extends CalendarDateTime ? CalendarDateTime :
748
CalendarDate;
749
type MappedTimeValue<T> = T extends Time ? Time : Time;
750
751
// Range types
752
interface RangeValue<T> {
753
/** Range start value */
754
start: T;
755
/** Range end value */
756
end: T;
757
}
758
759
// Calendar types
760
interface CalendarDate {
761
readonly calendar: Calendar;
762
readonly era: string;
763
readonly year: number;
764
readonly month: number;
765
readonly day: number;
766
767
copy(): CalendarDate;
768
add(duration: DateDuration): CalendarDate;
769
subtract(duration: DateDuration): CalendarDate;
770
set(fields: DateFields): CalendarDate;
771
cycle(field: DateField, amount: number): CalendarDate;
772
toString(): string;
773
toDate(timeZone: string | TimeZone): Date;
774
compare(other: CalendarDate): number;
775
}
776
777
interface CalendarDateTime extends CalendarDate {
778
readonly hour: number;
779
readonly minute: number;
780
readonly second: number;
781
readonly millisecond: number;
782
783
copy(): CalendarDateTime;
784
add(duration: DateTimeDuration): CalendarDateTime;
785
subtract(duration: DateTimeDuration): CalendarDateTime;
786
set(fields: DateTimeFields): CalendarDateTime;
787
}
788
789
interface ZonedDateTime extends CalendarDateTime {
790
readonly timeZone: string;
791
readonly offset: number;
792
793
copy(): ZonedDateTime;
794
add(duration: DateTimeDuration): ZonedDateTime;
795
subtract(duration: DateTimeDuration): ZonedDateTime;
796
set(fields: DateTimeFields): ZonedDateTime;
797
}
798
799
interface Time {
800
readonly hour: number;
801
readonly minute: number;
802
readonly second: number;
803
readonly millisecond: number;
804
805
copy(): Time;
806
add(duration: TimeDuration): Time;
807
subtract(duration: TimeDuration): Time;
808
set(fields: TimeFields): Time;
809
toString(): string;
810
compare(other: Time): number;
811
}
812
813
// Date field types
814
interface DateFields {
815
era?: string;
816
year?: number;
817
month?: number;
818
day?: number;
819
}
820
821
interface TimeFields {
822
hour?: number;
823
minute?: number;
824
second?: number;
825
millisecond?: number;
826
}
827
828
interface DateTimeFields extends DateFields, TimeFields {}
829
830
// Duration types
831
interface DateDuration {
832
years?: number;
833
months?: number;
834
weeks?: number;
835
days?: number;
836
}
837
838
interface TimeDuration {
839
hours?: number;
840
minutes?: number;
841
seconds?: number;
842
milliseconds?: number;
843
}
844
845
interface DateTimeDuration extends DateDuration, TimeDuration {}
846
847
// State interfaces
848
interface CalendarState {
849
readonly value: CalendarDate | null;
850
readonly anchorDate: CalendarDate;
851
readonly isDisabled: boolean;
852
readonly isReadOnly: boolean;
853
readonly isInvalid: boolean;
854
readonly visibleRange: RangeValue<CalendarDate>;
855
856
setValue(value: CalendarDate | null): void;
857
setAnchorDate(date: CalendarDate): void;
858
focusNextPage(): void;
859
focusPreviousPage(): void;
860
selectDate(date: CalendarDate): void;
861
isSelected(date: CalendarDate): boolean;
862
isCellDisabled(date: CalendarDate): boolean;
863
isCellUnavailable(date: CalendarDate): boolean;
864
}
865
866
interface RangeCalendarState {
867
readonly value: RangeValue<CalendarDate> | null;
868
readonly anchorDate: CalendarDate;
869
readonly isDisabled: boolean;
870
readonly isReadOnly: boolean;
871
readonly isInvalid: boolean;
872
readonly visibleRange: RangeValue<CalendarDate>;
873
readonly highlightedRange: RangeValue<CalendarDate> | null;
874
875
setValue(value: RangeValue<CalendarDate> | null): void;
876
setAnchorDate(date: CalendarDate): void;
877
highlightDate(date: CalendarDate): void;
878
selectDate(date: CalendarDate): void;
879
isSelected(date: CalendarDate): boolean;
880
isSelectionStart(date: CalendarDate): boolean;
881
isSelectionEnd(date: CalendarDate): boolean;
882
}
883
884
interface DateFieldState {
885
readonly value: DateValue | null;
886
readonly dateValue: CalendarDate | null;
887
readonly timeValue: Time | null;
888
readonly segments: DateSegment[];
889
readonly isDisabled: boolean;
890
readonly isReadOnly: boolean;
891
readonly isRequired: boolean;
892
readonly isInvalid: boolean;
893
readonly validationErrors: string[];
894
895
setValue(value: DateValue | null): void;
896
setSegment(field: DateField, value: number): void;
897
increment(field: DateField): void;
898
decrement(field: DateField): void;
899
confirmPlaceholder(): void;
900
}
901
902
interface TimeFieldState {
903
readonly value: Time | null;
904
readonly segments: DateSegment[];
905
readonly isDisabled: boolean;
906
readonly isReadOnly: boolean;
907
readonly isRequired: boolean;
908
readonly isInvalid: boolean;
909
readonly validationErrors: string[];
910
911
setValue(value: Time | null): void;
912
setSegment(field: TimeField, value: number): void;
913
increment(field: TimeField): void;
914
decrement(field: TimeField): void;
915
}
916
917
interface DatePickerState extends DateFieldState {
918
readonly isOpen: boolean;
919
readonly calendarState: CalendarState;
920
921
setOpen(isOpen: boolean): void;
922
open(): void;
923
close(): void;
924
}
925
926
interface DateRangePickerState {
927
readonly value: RangeValue<DateValue> | null;
928
readonly isOpen: boolean;
929
readonly calendarState: RangeCalendarState;
930
readonly startFieldState: DateFieldState;
931
readonly endFieldState: DateFieldState;
932
933
setValue(value: RangeValue<DateValue> | null): void;
934
setOpen(isOpen: boolean): void;
935
open(): void;
936
close(): void;
937
}
938
939
// Segment types
940
interface DateSegment {
941
type: DateField | TimeField;
942
text: string;
943
value: number | null;
944
minValue: number;
945
maxValue: number;
946
isEditable: boolean;
947
isPlaceholder: boolean;
948
}
949
950
type DateField = "era" | "year" | "month" | "day";
951
type TimeField = "dayPeriod" | "hour" | "minute" | "second" | "millisecond";
952
953
// Validation types
954
type ValidationError = string | string[];
955
956
interface ValidationResult {
957
isInvalid: boolean;
958
validationErrors: string[];
959
validationDetails: ValidationDetails;
960
}
961
962
interface ValidationDetails {
963
[key: string]: any;
964
}
965
```
966
967
## Integration Examples
968
969
### Complete Date Management System
970
971
```typescript
972
import {
973
DatePicker, DateRangePicker, Calendar, TimeInput,
974
Card, CardHeader, CardBody, Button, Divider
975
} from "@nextui-org/react";
976
import {
977
CalendarDate, Time, now, getLocalTimeZone,
978
isWeekend, isSameDay, startOfWeek, endOfWeek
979
} from "@internationalized/date";
980
981
function DateManagementSystem() {
982
const [selectedDate, setSelectedDate] = useState<CalendarDate | null>(null);
983
const [meetingTime, setMeetingTime] = useState<Time>(new Time(9, 0));
984
const [projectRange, setProjectRange] = useState<RangeValue<CalendarDate> | null>(null);
985
const today = now(getLocalTimeZone()).date;
986
987
const isUnavailable = (date: CalendarDate) => {
988
// Block weekends and holidays
989
return isWeekend(date, "en-US") ||
990
isSameDay(date, new CalendarDate(2024, 12, 25)) ||
991
isSameDay(date, new CalendarDate(2024, 1, 1));
992
};
993
994
const handleScheduleMeeting = () => {
995
if (selectedDate && meetingTime) {
996
console.log(`Meeting scheduled for ${selectedDate} at ${meetingTime}`);
997
}
998
};
999
1000
return (
1001
<div className="max-w-4xl mx-auto space-y-6">
1002
<Card>
1003
<CardHeader>
1004
<h2 className="text-xl font-bold">Meeting Scheduler</h2>
1005
</CardHeader>
1006
<CardBody className="space-y-4">
1007
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
1008
<DatePicker
1009
label="Meeting Date"
1010
value={selectedDate}
1011
onChange={setSelectedDate}
1012
minValue={today}
1013
isDateUnavailable={isUnavailable}
1014
description="Select a business day"
1015
showMonthAndYearPickers
1016
/>
1017
1018
<TimeInput
1019
label="Meeting Time"
1020
value={meetingTime}
1021
onChange={setMeetingTime}
1022
minValue={new Time(8, 0)}
1023
maxValue={new Time(18, 0)}
1024
description="Business hours only"
1025
/>
1026
</div>
1027
1028
<Button
1029
color="primary"
1030
onPress={handleScheduleMeeting}
1031
isDisabled={!selectedDate}
1032
>
1033
Schedule Meeting
1034
</Button>
1035
</CardBody>
1036
</Card>
1037
1038
<Card>
1039
<CardHeader>
1040
<h2 className="text-xl font-bold">Project Timeline</h2>
1041
</CardHeader>
1042
<CardBody>
1043
<DateRangePicker
1044
label="Project Duration"
1045
value={projectRange}
1046
onChange={setProjectRange}
1047
minValue={today}
1048
visibleMonths={2}
1049
validate={(range) => {
1050
if (!range) return "Please select a project timeline";
1051
const duration = range.end.calendar.toJulianDay(range.end) -
1052
range.start.calendar.toJulianDay(range.start);
1053
if (duration < 7) return "Project must be at least 1 week";
1054
if (duration > 365) return "Project cannot exceed 1 year";
1055
return true;
1056
}}
1057
errorMessage={(validation) =>
1058
validation.isInvalid ? validation.validationErrors[0] : undefined
1059
}
1060
/>
1061
</CardBody>
1062
</Card>
1063
1064
<Card>
1065
<CardHeader>
1066
<h2 className="text-xl font-bold">Calendar Overview</h2>
1067
</CardHeader>
1068
<CardBody>
1069
<Calendar
1070
value={selectedDate}
1071
onChange={setSelectedDate}
1072
minValue={startOfWeek(today, "en-US")}
1073
maxValue={endOfWeek(today.add({ months: 2 }), "en-US")}
1074
isDateUnavailable={isUnavailable}
1075
visibleMonths={2}
1076
color="secondary"
1077
className="w-full"
1078
/>
1079
</CardBody>
1080
</Card>
1081
</div>
1082
);
1083
}
1084
```