or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-system.mddata-display.mddate-time.mdfeedback.mdforms.mdindex.mdinputs.mdinteractions.mdlayout.mdnavigation.mdoverlays.mdutilities.md

date-time.mddocs/

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

```