Date Picker

Date Picker is an input field that allows the user to enter a date by typing or by selecting from a calendar overlay.

Open in a
new tab
DatePicker datePicker = new DatePicker("Start date");
add(datePicker);

The date can be entered directly using the keyboard in the format of the current locale or through the date picker overlay. The overlay opens when the field is clicked and/or any input is entered when the field is focused.

Common Input Field Features

Date Picker includes all Text Field and shared input field features.

Date Format

The date picker can be configured to display dates and parse user input in a specific format.

Using Java Locales

The date picker can be configured to display dates and parse user input in a specific format. By default, the date picker displays and parses dates using the user’s locale (reference). Alternatively, setting a specific locale ensures that all users consistently see the same format.

Open in a
new tab
Locale finnishLocale = new Locale("fi", "FI");

DatePicker datePicker = new DatePicker("Select a date:");
datePicker.setLocale(finnishLocale);

The date format that is used based on the locale depends on the specific browser implementation and might not be reliable when expecting a specific pattern.

Validation

Min & Max Value

The valid input range of Date Picker can be restricted by defining min and max values. Dates before the min and after the max are disabled in the overlay. A helper text can be used to inform the user about the accepted range.

Open in a
new tab
LocalDate now = LocalDate.now(ZoneId.systemDefault());

datePicker.setMin(now);
datePicker.setMax(now.plusDays(60));
datePicker.setHelperText("Must be within 60 days from today");

Custom Validation

Date Picker supports custom validation, such as limiting the options to Monday through Friday.

Open in a
new tab
DatePicker datePicker = new DatePicker("Meeting date");
datePicker.setHelperText("Mondays – Fridays only");

Binder<Appointment> binder = new Binder<>(Appointment.class);
binder.forField(datePicker)
        .withValidator(localDate -> {
            int dayOfWeek = localDate.getDayOfWeek().getValue();
            boolean validWeekDay = dayOfWeek >= 1 && dayOfWeek <= 5;
            return validWeekDay;
        }, "Please select a weekday")
        .bind(Appointment::getStartDate, Appointment::setStartDate);

Week Numbers

Week numbers (ISO-8601) can be enabled in the calendar overlay. This works only when the first day of the week is set to Monday.

Open in a
new tab
datePicker.setWeekNumbersVisible(true);
datePicker.setI18n(new DatePicker.DatePickerI18n().setFirstDayOfWeek(1));

Initial Position

Date Picker’s initial position parameter defines which date is focused in the calendar overlay when the overlay is opened. The default initial position is the selected or current date.

Use this feature to minimise the need for unnecessary navigation and/or scrolling when the user’s input is expected to be within a certain time.

Open in a
new tab
LocalDate lastDayOfYear = LocalDate.now(ZoneId.systemDefault())
        .with(TemporalAdjusters.lastDayOfYear());

datePicker.setInitialPosition(lastDayOfYear);

Auto Open

The overlay automatically opens when the field is focused. This can be prevented, to have the overlay only open when the toggle button or Up/Down arrow keys are pressed. Note, that the behavior is not affected on touch devices.

Open in a
new tab
datePicker.setAutoOpen(false);

Usage Patterns

Date Range

You can create a date range picker using two Date Pickers.

Open in a
new tab
DatePicker departureDate = new DatePicker("Departure date");
DatePicker returnDate = new DatePicker("Return date");
departureDate.addValueChangeListener(e -> returnDate.setMin(e.getValue()));
returnDate.addValueChangeListener(e -> departureDate.setMax(e.getValue()));

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.

Best Practises

Picking vs Typing

The calendar overlay is useful when the users need to choose a day that is close to the current date or when information such as day of the week, week number, and valid dates, etc. can aid in choosing the best option.

For days well in the past or future, and for known dates such as birthdays, typing the date in the input field can be the faster and easier approach. Because of this, it is important to verify that the user can enter dates according to their locale.

Instead of a Date Picker, you can use individual input fields for day, month, and year, to improve usability on small touch devices.

Open in a
new tab
public DatePickerIndividualInputFields() {
    LocalDate now = LocalDate.now(ZoneId.systemDefault());

    List<Integer> selectableYears = IntStream.range(
            now.getYear() - 99,
            now.getYear() + 1)
            .boxed().collect(Collectors.toList());

    yearPicker = new ComboBox<>("Year", selectableYears);
    yearPicker.setWidth(6, Unit.EM);
    yearPicker.addValueChangeListener(e -> {
        updateMonthPicker();
        updateDayPicker();
    });

    monthPicker = new ComboBox<>("Month", Month.values());
    monthPicker.setItemLabelGenerator(m -> m.getDisplayName(
            TextStyle.FULL,
            Locale.getDefault()
    ));
    monthPicker.setWidth(9, Unit.EM);
    monthPicker.addValueChangeListener(e -> {
        updateDayPicker();
    });
    monthPicker.setEnabled(false);

    dayPicker = new ComboBox<>("Day");
    dayPicker.setWidth(5, Unit.EM);
    dayPicker.setEnabled(false);

    add(new HorizontalLayout(yearPicker, monthPicker, dayPicker));
}

private void updateMonthPicker() {
    if (yearPicker.getValue() == null) {
        monthPicker.setValue(null);
        monthPicker.setEnabled(false);
        return;
    }

    monthPicker.setValue(null);
    monthPicker.setEnabled(true);
}

private void updateDayPicker() {
    if (yearPicker.getValue() == null || monthPicker.getValue() == null) {
        dayPicker.setValue(null);
        dayPicker.setEnabled(false);
        return;
    }

    dayPicker.setValue(null);
    dayPicker.setEnabled(true);

    LocalDate startOfMonth = LocalDate.of(
            yearPicker.getValue(),
            monthPicker.getValue(),
            1
    );
    int lengthOfMonth = startOfMonth.lengthOfMonth();

    dayPicker.setItems(IntStream.range(1, lengthOfMonth + 1)
                               .boxed()
                               .collect(Collectors.toList()));
}
Note
Not production-ready

The above example is only a prototype implementation to demonstrate the idea, and not ready for production use.

Show the Date Format

Use a placeholder or helper to show how the input should be formatted. For example, 12/6/2020 represents different dates for Americans and Europeans.

Open in a
new tab
datePicker.setPlaceholder("DD.MM.YYYY");
datePicker.setHelperText("Format: DD.MM.YYYY");

Helpers are preferable to placeholders, as they are always visible. Fields with placeholders are also less noticeable than empty fields and susceptible to being skipped. Use placeholders when space is limited, for example, when Date Picker is used as a filter in a data grid header.

ComponentUsage recommendations

Time Picker

Input field for entering or selecting a specific time.

Date Time Picker

Input field for selecting both a date and a time.