> Markdown version of [Date Time Picker](https://vaadin.com/docs/next/components/date-time-picker). Section index: [llms.txt](https://vaadin.com/docs/next/components/llms.txt)

# Date Time Picker

Date Time Picker is an input field for selecting both a date and a time.

**Lit** — `date-time-picker-basic.ts`

```html
<vaadin-date-time-picker label="Meeting date and time"></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerBasic.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setLabel("Meeting date and time");
add(dateTimePicker);
```

**React** — `date-time-picker-basic.tsx`

```tsx
<DateTimePicker label="Meeting date and time" />
```

The date and time can be entered directly using the keyboard in the format of the current locale or through the Date Time Picker’s two overlays. The overlays open when their respective fields are clicked or any input is entered when the fields are focused.

## <a id="step"></a>Step

Date Time Picker’s step parameter defines the time interval in seconds between the items displayed in the time picker overlay. It also specifies the amount by which the time increases or decreases using the up and down arrow keys when the overlays are disabled.

The default step is one hour (that is, `3600`). Unlike with [Number Field](https://vaadin.com/docs/next/components/number-field.md), Date Time Picker accepts values that don’t align with the specified step.

**Lit** — `date-time-picker-minutes-step.ts`

```html
<vaadin-date-time-picker
  label="Meeting date and time"
  value="2020-06-12T12:30"
  .step="${60 * 30}"
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerMinutesStep.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setLabel("Meeting date and time");
dateTimePicker.setStep(Duration.ofMinutes(30));
dateTimePicker.setValue(LocalDateTime.of(2020, 6, 12, 12, 30, 0));
add(dateTimePicker);
```

**React** — `date-time-picker-minutes-step.tsx`

```tsx
<DateTimePicker label="Meeting date and time" value="2020-06-12T12:30" step={60 * 30} />
```

> **Note: Use Even Steps**
>
> The step must divide evenly an hour or a day. For example, *"15 minutes"*, *"30 minutes"* and *"2 hours"* are valid steps, while *"42 minutes"* isn’t.

The displayed time format changes based on the step.

**Lit** — `date-time-picker-seconds-step.ts`

```html
<vaadin-date-time-picker
  label="Message received"
  value="2020-06-12T15:45:08"
  step="1"
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerSecondsStep.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setLabel("Message received");
dateTimePicker.setStep(Duration.ofSeconds(1));
dateTimePicker.setValue(LocalDateTime.of(2020, 6, 12, 15, 45, 8));
add(dateTimePicker);
```

**React** — `date-time-picker-seconds-step.tsx`

```tsx
<DateTimePicker label="Message received" value="2020-06-12T15:45:08" step={1} />
```

<!-- vale Vaadin.Abbr = NO -->

| Step                 | Format       |
| -------------------- | ------------ |
| Less than 60 seconds | HH:MM:SS     |
| Less than 1 second   | HH:MM:SS:FFF |

<!-- vale Vaadin.Abbr = YES -->

> **Note: Limit Number of Steps**
>
> The overlay doesn’t appear for steps less than 900 seconds (i.e., 15 minutes) to avoid showing an impractical number of choices.

## <a id="auto-open"></a>Auto Open

The overlay opens automatically when the field is focused using a pointer (i.e., mouse or touch), or when the user types in the field. You can disable this so that the overlay opens only when the toggle button or the `Up`/`Down` arrow keys are pressed.

**Lit** — `date-time-picker-auto-open.ts`

```html
<vaadin-date-time-picker
  label="Meeting date and time"
  auto-open-disabled
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerAutoOpen.java`

```java
dateTimePicker.setAutoOpen(false);
```

**React** — `date-time-picker-auto-open.tsx`

```tsx
<DateTimePicker label="Meeting date and time" autoOpenDisabled />
```

## <a id="validation"></a>Validation

Date Time Picker provides a validation mechanism based on constraints. Constraints allow you to define criteria that the date must meet to be considered valid. Validation occurs typically when the user initiates a date change, for example by selecting a date from the overlay or through text input followed by `Enter`. If the date is invalid, the field is highlighted in red, and an error message appears underneath the input.

Below is a list of supported constraints with more detailed information:

Bad Input

Bad input refers to any input that cannot be parsed into a value of the field type. When an unparsable value is entered, the field resets the value to empty and becomes invalid. This constraint is non-configurable and enabled by default.

Required

Required fields are marked with an indicator next to the label, and become invalid if their value is first entered and then cleared.

An instruction text at the top of the form explaining the required indicator is recommended. The indicator itself can be customized with the `--vaadin-input-field-required-indicator` style property.

Incomplete Input

Incomplete input refers to when an input has a valid value while the other is empty. When an incomplete value is entered, the field resets the value to empty and becomes invalid. This constraint is non-configurable and enabled by default.

Min & Max Values

The valid input range of Date Time Picker can be restricted by defining `min` and `max` values. Dates and times before the `min` and after the `max` aren’t available for selection in the overlay. Helper text can be used to inform the user about the accepted range.

The following example demonstrates how to specify these constraints and provide error messages:

**Lit** — `date-time-picker-validation.ts`

```html
<vaadin-date-time-picker
  required
  label="Appointment date and time"
  helper-text="Must be within 60 days from today"
  .min="${format(this.minDate, `yyyy-MM-dd'T'HH:00:00`)}"
  .max="${format(this.maxDate, `yyyy-MM-dd'T'HH:00:00`)}"
  .errorMessage="${this.errorMessage}"
  @validated="${(event: DateTimePickerValidatedEvent) => {
    const field = event.target as DateTimePicker;
    const datePicker: DatePicker = field.querySelector('[slot=date-picker]')!;
    const timePicker: TimePicker = field.querySelector('[slot=time-picker]')!;
    const hasBadDateInput =
      !datePicker.value && !!(datePicker.inputElement as HTMLInputElement).value;
    const hasBadTimeInput =
      !timePicker.value && !!(timePicker.inputElement as HTMLInputElement).value;
    const hasIncompleteInput =
      (datePicker.value && !timePicker.value) || (timePicker.value && !datePicker.value);

    if (hasBadDateInput || hasBadTimeInput) {
      this.errorMessage = 'Invalid date or time';
    } else if (hasIncompleteInput) {
      this.errorMessage = 'Missing date or time';
    } else if (!field.value) {
      this.errorMessage = 'Field is required';
    } else if (field.value < field.min!) {
      this.errorMessage = 'Too early, choose another date and time';
    } else if (field.value > field.max!) {
      this.errorMessage = 'Too late, choose another date and time';
    } else {
      this.errorMessage = '';
    }
  }}"
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerValidation.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setRequiredIndicatorVisible(true);
dateTimePicker.setLabel("Appointment date and time");
dateTimePicker.setHelperText("Must be within 60 days from today");
dateTimePicker.setMin(LocalDateTime.now());
dateTimePicker.setMax(LocalDateTime.now().plusDays(60));

dateTimePicker.setI18n(new DateTimePickerI18n()
        .setRequiredErrorMessage("Field is required")
        .setBadInputErrorMessage("Invalid date or time format")
        .setIncompleteInputErrorMessage("Missing date or time")
        .setMinErrorMessage("Too early, choose another date and time")
        .setMaxErrorMessage("Too late, choose another date and time"));

add(dateTimePicker);
```

**React** — `date-time-picker-validation.tsx`

```tsx
function Example() {
  const errorMessage = useSignal('');
  const minDate = useSignal(new Date());
  const maxDate = useSignal(addDays(new Date(), 60));

  return (
    <DateTimePicker
      label="Appointment date and time"
      helperText="Must be within 60 days from today"
      min={format(minDate.value, `yyyy-MM-dd'T'HH:00:00`)}
      max={format(maxDate.value, `yyyy-MM-dd'T'HH:00:00`)}
      errorMessage={errorMessage.value}
      onValidated={(event) => {
        const field = event.target as DateTimePickerElement;
        const datePicker: DatePickerElement = field.querySelector('[slot=date-picker]')!;
        const timePicker: TimePickerElement = field.querySelector('[slot=time-picker]')!;
        const hasBadDateInput =
          !datePicker.value && !!(datePicker.inputElement as HTMLInputElement).value;
        const hasBadTimeInput =
          !timePicker.value && !!(timePicker.inputElement as HTMLInputElement).value;
        const hasIncompleteInput =
          (datePicker.value && !timePicker.value) || (timePicker.value && !datePicker.value);

        if (hasBadDateInput || hasBadTimeInput) {
          errorMessage.value = 'Invalid date or time';
        } else if (hasIncompleteInput) {
          errorMessage.value = 'Missing date or time';
        } else if (!field.value) {
          errorMessage.value = 'Field is required';
        } else if (field.value < field.min!) {
          errorMessage.value = 'Too early, choose another date and time';
        } else if (field.value > field.max!) {
          errorMessage.value = 'Too late, choose another date and time';
        } else {
          errorMessage.value = '';
        }
      }}
    />
  );
}
```

It’s important to ensure an appropriate error message is configured for each constraint violation to provide users with clear feedback.

### <a id="custom-validation"></a>Custom Validation

For more complex cases where constraint validation isn’t enough, Flow and Hilla offer the Binder API that allows you to define custom validation rules. This is useful, for example, when you want to restrict date selection to weekdays (i.e., Monday - Friday) and time selection to only certain hours. In the following example, try selecting a date that’s on a weekend or a time that’s outside opening hours to see a custom validation message.

**Lit** — `date-time-picker-custom-validation.ts`

```html
private binder = new Binder(this, AppointmentModel);

private errorMessage = 'The selected day of week or time is not available';

protected override firstUpdated() {
  this.binder.for(this.binder.model.startDateTime).addValidator({
    message: this.errorMessage,
    validate: (startDateTime: string) => {
      const date = new Date(startDateTime);
      const validWeekDay = date.getDay() >= 1 && date.getDay() <= 5;
      return validWeekDay;
    },
  });
  this.binder.for(this.binder.model.startDateTime).addValidator({
    message: this.errorMessage,
    validate: (startDateTime: string) => {
      const time = startDateTime.split('T')[1];
      const validTime =
        (time >= '08:00' && time <= '12:00') || (time >= '13:00' && time <= '16:00');
      return validTime;
    },
  });
}

protected override render() {
  return html`
    <vaadin-date-time-picker
      label="Appointment date and time"
      helper-text="Open Mondays-Fridays, 8:00-12:00, 13:00-16:00"
      .step="${60 * 30}"
      ${field(this.binder.model.startDateTime)}
    ></vaadin-date-time-picker>
  `;
}
```

**Flow** — `DateTimePickerCustomValidation.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setLabel("Appointment date and time");
dateTimePicker
        .setHelperText("Open Mondays-Fridays, 8:00-12:00, 13:00-16:00");
dateTimePicker.setStep(Duration.ofMinutes(30));
dateTimePicker.setI18n(new DateTimePickerI18n()
        .setBadInputErrorMessage("Invalid date or time format")
        .setIncompleteInputErrorMessage("Missing date or time"));
add(dateTimePicker);

String errorMessage = "The selected day of week or time is not available";
Binder<Appointment> binder = new Binder<>(Appointment.class);
binder.forField(dateTimePicker).withValidator(startDateTime -> {
    boolean validWeekDay = startDateTime.getDayOfWeek().getValue() >= 1
            && startDateTime.getDayOfWeek().getValue() <= 5;
    return validWeekDay;
}, errorMessage).withValidator(startDateTime -> {
    LocalTime startTime = LocalTime.of(startDateTime.getHour(),
            startDateTime.getMinute());
    boolean validTime = !(LocalTime.of(8, 0).isAfter(startTime)
            || (LocalTime.of(12, 0).isBefore(startTime)
                    && LocalTime.of(13, 0).isAfter(startTime))
            || LocalTime.of(16, 0).isBefore(startTime));
    return validTime;
}, errorMessage).bind(Appointment::getStartDateTime,
        Appointment::setStartDateTime);
```

**React** — `date-time-picker-custom-validation.tsx`

```tsx
const { model, field } = useForm(AppointmentModel);
const dateTimeField = useFormPart(model.startDateTime);
const errorMessage = 'The selected day of week or time is not available';

useEffect(() => {
  dateTimeField.addValidator({
    message: errorMessage,
    validate: (startDateTime: string) => {
      const date = new Date(startDateTime);
      const isWeekday = date.getDay() >= 1 && date.getDay() <= 5;
      return isWeekday;
    },
  });

  dateTimeField.addValidator({
    message: errorMessage,
    validate: (startDateTime: string) => {
      const time = startDateTime.split('T')[1];
      const validTime =
        (time >= '08:00' && time <= '12:00') || (time >= '13:00' && time <= '16:00');
      return validTime;
    },
  });
}, []);

return (
  <DateTimePicker
    label="Appointment date and time"
    helperText="Open Mondays-Fridays, 8:00-12:00, 13:00-16:00"
    step={60 * 30}
    {...field(model.startDateTime)}
  />
);
```

Binder can also be used to organize data binding and validation for multiple fields, creating forms. You can learn more about Binder from the corresponding [Flow](https://vaadin.com/docs/next/flow/binding-data/components-binder-validation.md) and [Hilla](https://vaadin.com/docs/next/hilla/guides/forms/binder-validation.md) articles.

## <a id="week-numbers"></a>Week Numbers

You can configure Date Time Picker to show week numbers in the date picker overlay.

**Lit** — `date-time-picker-week-numbers.ts`

```html
@query('vaadin-date-time-picker')
private dateTimePicker!: DateTimePicker;

protected override firstUpdated() {
  this.dateTimePicker.i18n = {
    ...this.dateTimePicker.i18n,
    firstDayOfWeek: 1,
  };
}

protected override render() {
  return html`
    <vaadin-date-time-picker
      label="Meeting date and time"
      show-week-numbers
    ></vaadin-date-time-picker>
  `;
}
```

**Flow** — `DateTimePickerWeekNumbers.java`

```java
dateTimePicker.setWeekNumbersVisible(true);
dateTimePicker.setDatePickerI18n(
        new DatePicker.DatePickerI18n().setFirstDayOfWeek(1));
```

**React** — `date-time-picker-week-numbers.tsx`

```tsx
const dateTimePicker = useRef<DateTimePickerElement>(null);

useEffect(() => {
  if (dateTimePicker.current) {
    dateTimePicker.current.i18n = {
      ...dateTimePicker.current.i18n,
      firstDayOfWeek: 1,
    };
  }
}, [dateTimePicker.current]);

return <DateTimePicker ref={dateTimePicker} label="Meeting date and time" showWeekNumbers />;
```

The week numbers are displayed according to [ISO-8601](https://www.iso.org/iso-8601-date-and-time-format.html). They can only be displayed with the first day of the week set to Monday.

## <a id="initial-position"></a>Initial Position

Date Time Picker’s initial position parameter defines which date is focused in the calendar overlay when the overlay is opened. Use this feature to minimize the need for any additional navigation or scrolling when the user’s input is expected to be between certain dates.

**Lit** — `date-time-picker-initial-position.ts`

```html
<vaadin-date-time-picker
  label="Meeting date and time"
  .initialPosition="${startOfNextMonthISOString}"
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerInitialPosition.java`

```java
// https://github.com/vaadin/vaadin-date-time-picker/issues/57
DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE;
LocalDate startOfNextMonth = LocalDate.now(ZoneId.systemDefault())
        .with(TemporalAdjusters.firstDayOfNextMonth());
String startOfNextMonthIsoString = formatter.format(startOfNextMonth);

dateTimePicker.getElement().executeJs("this.initialPosition = $0",
        startOfNextMonthIsoString);
```

**React** — `date-time-picker-initial-position.tsx`

```tsx
<DateTimePicker label="Meeting date and time" initialPosition={startOfNextMonthISOString} />
```

## <a id="default-time"></a>Default Time (since V25.3)

Date Time Picker’s default time defines the time that’s filled in automatically when the user selects a date while the time field is empty. This saves the user from entering a time in applications where a certain time of day is the most likely choice, such as the start of the working day.

The default time is only applied to dates the user selects; it doesn’t affect values set programmatically. A time the user has already entered is never overwritten, but clearing the time field and selecting another date applies the default time again.

The applied time follows the precision defined by the step: a more precise default time is truncated. A default time outside the allowed range is applied as it is, which makes the field invalid.

**Lit** — `date-time-picker-default-time.ts`

```html
<vaadin-date-time-picker label="Appointment" default-time="09:00"></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerDefaultTime.java`

```java
DateTimePicker dateTimePicker = new DateTimePicker("Appointment");
dateTimePicker.setDefaultTime(LocalTime.of(9, 0));
```

**React** — `date-time-picker-default-time.tsx`

```tsx
<DateTimePicker label="Appointment" defaultTime="09:00" />
```

## <a id="internationalization-i18n"></a>Internationalization (i18n)

Date Time Picker allows localizing texts and labels, such as month names and button labels.

**Lit** — `date-time-picker-internationalization.ts`

```typescript
@query('vaadin-date-time-picker')
private dateTimePicker!: DateTimePicker;

protected override firstUpdated() {
  this.dateTimePicker.i18n = {
    ...this.dateTimePicker.i18n,
    monthNames: [
      'Januar',
      'Februar',
      'März',
      'April',
      'Mai',
      'Juni',
      'Juli',
      'August',
      'September',
      'Oktober',
      'November',
      'Dezember',
    ],
    weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
    weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
    today: 'Heute',
    cancel: 'Abbrechen',
    dateLabel: 'datum',
    timeLabel: 'zeit',
  };
}

protected override render() {
  return html`<vaadin-date-time-picker label="Sitzungsdatum"></vaadin-date-time-picker>`;
}
```

**Flow** — `DateTimePickerInternationalization.java`

```java
DatePicker.DatePickerI18n germanI18n = new DatePicker.DatePickerI18n();
germanI18n.setMonthNames(List.of("Januar", "Februar", "März", "April",
        "Mai", "Juni", "Juli", "August", "September", "Oktober",
        "November", "Dezember"));
germanI18n.setWeekdays(List.of("Sonntag", "Montag", "Dienstag",
        "Mittwoch", "Donnerstag", "Freitag", "Samstag"));
germanI18n.setWeekdaysShort(
        List.of("So", "Mo", "Di", "Mi", "Do", "Fr", "Sa"));
germanI18n.setToday("Heute");
germanI18n.setCancel("Abbrechen");

dateTimePicker.setDatePickerI18n(germanI18n);
```

**React** — `date-time-picker-internationalization.tsx`

```tsx
const dateTimePickerRef = useRef<DateTimePickerElement>(null);

useEffect(() => {
  if (dateTimePickerRef.current) {
    dateTimePickerRef.current.i18n = {
      ...dateTimePickerRef.current.i18n,
      monthNames: [
        'Januar',
        'Februar',
        'März',
        'April',
        'Mai',
        'Juni',
        'Juli',
        'August',
        'September',
        'Oktober',
        'November',
        'Dezember',
      ],
      weekdays: ['Sonntag', 'Montag', 'Dienstag', 'Mittwoch', 'Donnerstag', 'Freitag', 'Samstag'],
      weekdaysShort: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa'],
      today: 'Heute',
      cancel: 'Abbrechen',
      dateLabel: 'datum',
      timeLabel: 'zeit',
    };
  }
}, [dateTimePickerRef.current]);

return <DateTimePicker ref={dateTimePickerRef} label="Sitzungsdatum" />;
```

See also how to [configure a custom date format](https://vaadin.com/docs/next/components/date-picker.md#date-format).

## <a id="basic-features"></a>Basic Features

The following features, common to most input field components, are supported:

Label

The label is used to identify the input field. It supports plain-text content. In the Lumo theme its length is limited to the width of the field (and truncated with ellipsis), while in the Aura theme labels wrap to multiple lines. [Helpers](#helper) and [Tooltips](#tooltip) can be used to provide additional information that doesn’t fit into the label.

Visible labels are strongly recommended for all input fields. In cases where the built-in label cannot be used, an external element can be associated as the field’s label through the `aria-labelledby` attribute (`setAriaLabelledBy` in Flow). Fields without any visible label should include an invisible label for assistive technologies with the `aria-label` attribute (`setAriaLabel` in Flow).

Helper

Helpers are used to provide additional information that the user may need to enter in the field, such as format requirements or explanations of the field’s purpose below the field.

A [style variant](https://vaadin.com/docs/next/components/date-time-picker/styling.md#style-variants) is available for rendering the helper above the field.

In addition to plain text, helpers can contain components and HTML elements. However, complex and interactive content is likely to have accessibility issues.

Placeholder

The placeholder is text that’s displayed when the field is empty. Its primary purpose is to provide a short input hint (e.g., the expected format) in situations where a [Helper](#helper) cannot be used.

Placeholders should not be used as a replacement for a visible label. They can be mistaken for a manually entered value. See [Label](#label) for alternatives to the built-in field label.

Tooltip

Tooltips are small text pop-ups displayed on hover, and on keyboard-focus. They can be used to provide additional information about a field. This can be useful in situations where an always visible [Helper](#helper) is not appropriate. Helpers are generally recommended in favor of tooltips, though, as they provide much better discoverability and mobile support. See the [Tooltip](https://vaadin.com/docs/next/components/tooltip.md) documentation for more information.

Invisible Labels (ARIA)

If the built-in label cannot be used, an invisible label should be provided for users of assistive technologies like screen readers. The date and time sub-fields can also be assigned invisible suffixes (e.g., `date` and `time`) that are appended to their invisible labels.

```html
<!-- Invisible label for screen readers: -->
<date-time-picker accessible-name="Meeting">...
<!-- Suffixes for date and time sub-fields are set through the i18n object -->
```

```java
// Invisible label for screen readers:
field.setAriaLabel("Meeting");
// Suffixes for sub-fields:
field.setDateAriaLabel("date"); // -> "Meeting date"
field.setDateAriaLabel("time"); // -> "Meeting time"
```

**Lit** — `date-time-picker-basic-features.ts`

```typescript
<vaadin-date-time-picker
  label="Label"
  helper-text="Helper text"
  date-placeholder="Date"
  time-placeholder="Time"
>
  <vaadin-tooltip slot="tooltip" text="Tooltip text"></vaadin-tooltip>
</vaadin-date-time-picker>
```

**Flow** — `DateTimePickerBasicFeatures.java`

```java
DateTimePicker field = new DateTimePicker();
field.setLabel("Label");
field.setHelperText("Helper text");
field.setDatePlaceholder("Date");
field.setTimePlaceholder("Time");
field.setTooltipText("Tooltip text");
```

**React** — `date-time-picker-basic-features.tsx`

```tsx
<DateTimePicker
  label="Label"
  helperText="Helper text"
  datePlaceholder="Date"
  timePlaceholder="Time"
>
  <Tooltip slot="tooltip" text="Tooltip text" />
</DateTimePicker>
```

## <a id="read-only-disabled"></a>Read-Only & Disabled

Fields used to display values should be set to `read-only` mode to prevent editing. Read-only fields are focusable and visible to screen readers. They can display tooltips. Their values can be selected and copied.

Fields that are currently unavailable should be `disabled`. The reduced contrast of disabled fields makes them inappropriate for displaying information. They can’t be focused or display tooltips. They’re invisible to screen readers, and their values cannot be selected and copied.

Disabled fields can be useful in situations where they can become enabled based on some user action. Consider hiding fields entirely if there’s nothing the user can do to make them editable.

**Lit** — `date-time-picker-readonly-and-disabled.ts`

```typescript
<vaadin-date-time-picker readonly label="Read-only" value="2020-06-12T12:30">
</vaadin-date-time-picker>

<vaadin-date-time-picker disabled label="Disabled"></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerReadonlyAndDisabled.java`

```java
DateTimePicker readonlyField = new DateTimePicker();
readonlyField.setReadOnly(true);
readonlyField.setLabel("Read-only");
readonlyField.setValue(LocalDateTime.of(2020, 6, 12, 12, 30));

DateTimePicker disabledField = new DateTimePicker();
disabledField.setEnabled(false);
disabledField.setLabel("Disabled");
```

**React** — `date-time-picker-readonly-and-disabled.tsx`

```tsx
<DateTimePicker readonly label="Read-only" value="2020-06-12T12:30" />

<DateTimePicker disabled label="Disabled" />
```

## <a id="usage-patterns"></a>Usage Patterns

### <a id="date-time-range"></a>Date Time Range

You can accomplish a date time range picker using two Date Time Pickers.

**Lit** — `date-time-picker-range.ts`

```html
<vaadin-form-layout auto-responsive column-width="20rem">
  <vaadin-date-time-picker
    label="Start date and time"
    .value="${this.startDateTime}"
    @value-changed="${(event: DateTimePickerValueChangedEvent) => {
      this.startDateTime = event.detail.value;
    }}"
  ></vaadin-date-time-picker>

  <vaadin-date-time-picker
    label="End date and time"
    .min="${this.startDateTime}"
    .value="${this.endDateTime}"
    @value-changed="${(event: DateTimePickerValueChangedEvent) => {
      this.endDateTime = event.detail.value;
    }}"
  ></vaadin-date-time-picker>
</vaadin-form-layout>
```

**Flow** — `DateTimePickerRange.java`

```java
DateTimePicker startDateTimePicker = new DateTimePicker(
        "Start date and time");
startDateTimePicker.setValue(LocalDateTime.of(2020, 8, 25, 20, 0, 0));

DateTimePicker endDateTimePicker = new DateTimePicker(
        "End date and time");
endDateTimePicker.setValue(LocalDateTime.of(2020, 9, 1, 20, 0, 0));

startDateTimePicker.addValueChangeListener(
        e -> endDateTimePicker.setMin(e.getValue()));

add(startDateTimePicker, endDateTimePicker);
```

**React** — `date-time-picker-range.tsx`

```tsx
<FormLayout autoResponsive columnWidth="20rem">
  <DateTimePicker
    label="Start date and time"
    value={startDateTime.value}
    onValueChanged={(event) => {
      startDateTime.value = event.detail.value;
    }}
  />

  <DateTimePicker
    label="End date and time"
    min={startDateTime.value}
    value={endDateTime.value}
    onValueChanged={(event) => {
      endDateTime.value = event.detail.value;
    }}
  />
</FormLayout>
```

To disable the days before the start date in the end date picker, you need to handle the selection in the start date picker and change the range in the end date picker.

## <a id="best-practices"></a>Best Practices

Use Date Time Picker when the user needs to choose both a date and time of day. If you only need a date or time of day, use [Date Picker](https://vaadin.com/docs/next/components/date-picker.md) or [Time Picker](https://vaadin.com/docs/next/components/time-picker.md), respectively.

### <a id="picking-vs-typing"></a>Picking vs. Typing

The calendar overlay is useful when the user needs to choose a day that’s close to the current date or when information such as day of the week, week number, valid dates, and so on, can aid in choosing the best option.

For far off dates (i.e., years ago or years from now) and for known dates (i.e., holidays and birthdays), typing the date can be a faster and easier approach. It’s important to verify that the user can enter dates according to their locale.

### <a id="providing-input-guidance"></a>Providing Input Guidance

Use a helper text to show the expected date and time formats, and placeholders to help users identify the two sub-fields, correctly.

**Lit** — `date-time-picker-input-format.ts`

```html
<vaadin-date-time-picker
  label="Select date and time"
  helper-text="Format: DD/MM/YYYY and HH:MM"
  date-placeholder="Date"
  time-placeholder="Time"
></vaadin-date-time-picker>
```

**Flow** — `DateTimePickerInputFormat.java`

```java
DatePickerI18n dateFormat = new DatePickerI18n();
dateFormat.setDateFormat("dd/MM/yyyy");

DateTimePicker dateTimePicker = new DateTimePicker();
dateTimePicker.setLabel("Select date and time");
dateTimePicker.setDatePickerI18n(dateFormat);
dateTimePicker.setHelperText("Format: DD/MM/YYYY and HH:MM");
dateTimePicker.setDatePlaceholder("Date");
dateTimePicker.setTimePlaceholder("Time");
add(dateTimePicker);
```

**React** — `date-time-picker-input-format.tsx`

```tsx
<DateTimePicker
  label="Select date and time"
  helperText="Format: DD/MM/YYYY and HH:MM"
  datePlaceholder="Date"
  timePlaceholder="Time"
  ref={dateTimePickerRef}
/>
```

## <a id="related-components"></a>Related Components

| Component                                                             | Usage Recommendation                                   |
| --------------------------------------------------------------------- | ------------------------------------------------------ |
| [Time Picker](https://vaadin.com/docs/next/components/time-picker.md) | Input field for entering or selecting a specific time. |
| [Date Picker](https://vaadin.com/docs/next/components/date-picker.md) | Input field for entering or selecting a specific date. |

`58305ABE-B962-4ED0-A1C7-36BB906C9452`
