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

# Time Picker

Time Picker is an input field for used entering or selecting a specific time.

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

```html
<vaadin-time-picker label="Alarm" value="07:00"></vaadin-time-picker>
```

**Flow** — `TimePickerBasic.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setLabel("Alarm");
timePicker.setValue(LocalTime.of(7, 0));
add(timePicker);
```

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

```tsx
<TimePicker label="Alarm" value="07:00" />
```

The time can be entered directly using a keyboard, or by choosing a value from a set of predefined options presented in an overlay. The overlay opens when the field is clicked — or when any input is entered while the field is focused.

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

Time Picker’s step parameter defines the interval in seconds between the items displayed in the overlay. It also specifies the amount by which the time increases or decreases using the `Up` and `Down` arrow keys — when the overlay is disabled.

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

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

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

**Flow** — `TimePickerMinutesStep.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setLabel("Meeting time");
timePicker.setStep(Duration.ofMinutes(30));
timePicker.setValue(LocalTime.of(12, 30));
add(timePicker);
```

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

```tsx
<TimePicker label="Meeting time" value="12:30" step={60 * 30} />
```

> **Note: Use Common Steps**
>
> A step must evenly divide an hour or day. For example, *"15 minutes"* and *"30 minutes"* are valid steps for an hour, and *"2 hours"* is a valid step for a day, whereas *"42 minutes"* isn’t valid for either.

The displayed time format changes based on the step.

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

```html
<vaadin-time-picker label="Message received" value="15:45:08" step="1"></vaadin-time-picker>
```

**Flow** — `TimePickerSecondsStep.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setLabel("Message received");
timePicker.setStep(Duration.ofSeconds(1));
timePicker.setValue(LocalTime.of(15, 45, 8));
add(timePicker);
```

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

```tsx
<TimePicker label="Message received" value="15: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., a 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` or `Down` arrow keys — is pressed.

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

```html
<vaadin-time-picker
  label="Alarm"
  value="05:30"
  .step="${60 * 30}"
  auto-open-disabled
></vaadin-time-picker>
```

**Flow** — `TimePickerAutoOpen.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setLabel("Alarm");
timePicker.setStep(Duration.ofMinutes(30));
timePicker.setValue(LocalTime.of(5, 30));
timePicker.setAutoOpen(false);
add(timePicker);
```

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

```tsx
<TimePicker label="Alarm" value="05:30" step={60 * 30} autoOpenDisabled />
```

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

Time Picker provides a validation mechanism based on constraints. Constraints allow you to define criteria that the time must meet to be considered valid. Validation occurs typically when the user initiates a time change, for example by selecting a time from the overlay or through text input followed by `Enter`. If the time 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.

Min & Max Values

The valid input range of Time Picker can be restricted by defining `min` and `max` values. Times before the `min` and after the `max` aren’t displayed 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** — `time-picker-validation.ts`

```html
<vaadin-time-picker
  label="Appointment time"
  helper-text="Open 8:00-16:00"
  value="08:30"
  required
  min="08:00"
  max="16:00"
  .step="${60 * 30}"
  .errorMessage="${this.errorMessage}"
  @validated="${(event: TimePickerValidatedEvent) => {
    const field = event.target as TimePicker;
    if (!field.value && (field.inputElement as HTMLInputElement).value) {
      this.errorMessage = 'Invalid time format';
    } else if (!field.value) {
      this.errorMessage = 'Field is required';
    } else if (field.value < field.min) {
      this.errorMessage = 'Too early, choose another time';
    } else if (field.value > field.max) {
      this.errorMessage = 'Too late, choose another time';
    } else {
      this.errorMessage = '';
    }
  }}"
></vaadin-time-picker>
```

**Flow** — `TimePickerValidation.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setRequiredIndicatorVisible(true);
timePicker.setLabel("Appointment time");
timePicker.setHelperText("Open 8:00-16:00");
timePicker.setStep(Duration.ofMinutes(30));
timePicker.setValue(LocalTime.of(8, 30));
timePicker.setMin(LocalTime.of(8, 0));
timePicker.setMax(LocalTime.of(16, 0));

timePicker.setI18n(new TimePickerI18n()
        .setBadInputErrorMessage("Invalid time format")
        .setRequiredErrorMessage("Field is required")
        .setMinErrorMessage("Too early, choose another time")
        .setMaxErrorMessage("Too late, choose another time"));

add(timePicker);
```

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

```tsx
<TimePicker
  label="Appointment time"
  helper-text="Open 8:00-16:00"
  value={currentValue.value}
  required
  min="08:00"
  max="16:00"
  step={60 * 30}
  errorMessage={errorMessage.value}
  onValueChanged={(event) => {
    currentValue.value = event.detail.value;
  }}
  onValidated={(event) => {
    const field = event.target as TimePickerElement;
    if (!field.value && (field.inputElement as HTMLInputElement).value) {
      errorMessage.value = 'Invalid time format';
    } else if (!field.value) {
      errorMessage.value = 'Field is required';
    } else if (field.value < field.min) {
      errorMessage.value = 'Too early, choose another time';
    } else if (field.value > field.max) {
      errorMessage.value = 'Too late, choose another 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 allow time selection only within separate periods, like morning and afternoon slots. In the following example, try selecting a time that is between opening hours to see a custom validation message.

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

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

protected override firstUpdated() {
  this.binder.for(this.binder.model.startTime).addValidator({
    message: 'The selected time is not available',
    validate: (startTime: string) =>
      (startTime >= '08:00' && startTime <= '12:00') ||
      (startTime >= '13:00' && startTime <= '16:00'),
  });
}

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

**Flow** — `TimePickerCustomValidation.java`

```java
TimePicker timePicker = new TimePicker();
timePicker.setLabel("Appointment time");
timePicker.setHelperText("Open 8:00-12:00, 13:00-16:00");
timePicker.setStep(Duration.ofMinutes(30));
timePicker.setMin(LocalTime.of(8, 0));
timePicker.setMax(LocalTime.of(16, 0));
timePicker.setI18n(new TimePickerI18n()
        .setBadInputErrorMessage("Invalid time format"));
add(timePicker);

Binder<Appointment> binder = new Binder<>(Appointment.class);
binder.forField(timePicker).withValidator(startTime -> {
    return !(LocalTime.of(8, 0).isAfter(startTime)
            || (LocalTime.of(12, 0).isBefore(startTime)
                    && LocalTime.of(13, 0).isAfter(startTime))
            || LocalTime.of(16, 0).isBefore(startTime));
}, "The selected time is not available").bind(Appointment::getStartTime,
        Appointment::setStartTime);
```

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

```tsx
const { model, field } = useForm(AppointmentModel);
const timeField = useFormPart(model.startTime);

useEffect(() => {
  timeField.addValidator({
    message: 'The selected time is not available',
    validate: (startTime: string) =>
      (startTime >= '08:00' && startTime <= '12:00') ||
      (startTime >= '13:00' && startTime <= '16:00'),
  });
}, []);

return (
  <TimePicker
    label="Appointment time"
    helperText="Open 8:00-12:00, 13:00-16:00"
    min="08:00"
    max="16:00"
    step={60 * 30}
    {...field(model.startTime)}
  />
);
```

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/latest/flow/binding-data/components-binder-validation.md) and [Hilla](https://vaadin.com/docs/latest/hilla/guides/forms/binder-validation.md) articles.

## <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/latest/components/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/latest/components/tooltip.md) documentation for more information.

Clear Button

The clear button — which is displayed when the field is not empty — clears the field’s current value. Although the button itself is not keyboard focusable, the clear action can be taken with the `Esc` key, when the field has focus. The clear button can be especially useful in search and filter fields, where users often need to clear the value. They’re less useful, however, in regular forms.

Prefix

A prefix element — rendered at the start of the field — can be used to display units, icons, and similar visual cues to the field’s purpose or format.

Prefix elements aren’t automatically announced by screen readers as part of the field. Text content (e.g., in a `Span` or `Div`) that should be announced can be associated with the field (new in V25.3) using the `accessible-description-ref` attribute (`setAriaDescribedBy` in Flow). Focusable elements (e.g., buttons) are announced separately when focused.

```html
<vaadin-time-picker accessible-description-ref="currency-prefix">
  <span slot="prefix" id="currency-prefix">$</span>
</vaadin-time-picker>
```

```java
Span prefix = new Span("$");
field.setPrefixComponent(prefix);
field.setAriaDescribedBy(prefix);
```

Associated elements are announced in addition to the field’s helper and error message.

External & Invisible Labels (ARIA)

Visible labels are strongly recommended for all input fields. In situations where the built-in label cannot be used, an external element can be associated as the field’s label through its element `id`. Fields without any visible label should be provided an invisible label for assistive technologies like screen readers.

```html
<!-- Associates external element as label: -->
<label id="external-label">This is the label</label>
<vaadin-time-picker accessible-name-ref="external-label">...

<!-- Invisible label for screen readers: -->
<vaadin-time-picker accessible-name="This is the label">...
```

```java
// Associates external element as label:
NativeLabel label = new NativeLabel("This is the label");
label.setId("external-label");
field.setAriaLabelledBy("external-label");

// Invisible label for screen readers:
field.setAriaLabel("This is the label");
```

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

```typescript
<vaadin-time-picker
  label="Label"
  helper-text="Helper text"
  placeholder="Placeholder"
  clear-button-visible
>
  <vaadin-tooltip slot="tooltip" text="Tooltip text"></vaadin-tooltip>
  <vaadin-icon slot="prefix" icon="vaadin:vaadin-h"></vaadin-icon>
</vaadin-time-picker>
```

**Flow** — `TimePickerBasicFeatures.java`

```java
TimePicker field = new TimePicker();
field.setLabel("Label");
field.setHelperText("Helper text");
field.setPlaceholder("Placeholder");
field.setTooltipText("Tooltip text");
field.setClearButtonVisible(true);
field.setPrefixComponent(VaadinIcon.VAADIN_H.create());
```

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

```tsx
<TimePicker label="Label" helperText="Helper text" placeholder="Placeholder" clearButtonVisible>
  <Tooltip slot="tooltip" text="Tooltip text" />
  <Icon slot="prefix" icon="vaadin:vaadin-h" />
</TimePicker>
```

## <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** — `time-picker-readonly-and-disabled.ts`

```typescript
<vaadin-time-picker readonly label="Read-only" value="07:00"></vaadin-time-picker>

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

**Flow** — `TimePickerReadonlyAndDisabled.java`

```java
TimePicker readonlyField = new TimePicker();
readonlyField.setReadOnly(true);
readonlyField.setLabel("Read-only");
readonlyField.setValue(LocalTime.of(7, 0));

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

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

```tsx
<HorizontalLayout theme="spacing">
  <TimePicker readonly label="Read-only" value="07:00" />

  <TimePicker disabled label="Disabled" />
</HorizontalLayout>
```

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

Use Time Picker when the user needs to choose a time of day. Don’t use it for durations, such as for a stopwatch or timer.

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

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

`299E8D5A-A465-4F72-A029-BB24A4902CD3`
